Toggle Family
Toggle Family: anatomy, keyboard behavior, state, and theming in Askr.
Example
import { Toggle, ToggleGroup, ToggleGroupItem } from '@askrjs/themes/components';
<>
<Toggle pressed={bold()} onPress={() => setBold((value) => !value)}>Bold</Toggle>
<ToggleGroup type="single" value={alignment()} onValueChange={setAlignment}>
<ToggleGroupItem value="left">Left</ToggleGroupItem>
<ToggleGroupItem value="center">Center</ToggleGroupItem>
</ToggleGroup>
</>Published props
Generated from the TypeScript declarations shipped by the installed package. Named types in the Type column define the accepted values.
ToggleAsChildProps
Import from @askrjs/ui/toggle.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild: true; | — | — |
children | children: JSXElement; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
onPress | onPress?: ((e: PressEvent) => void) | undefined; | — | — |
pressed | pressed?: boolean | undefined; | — | — |
ref | ref?: Ref<Element>; | — | — |
type | type?: undefined; | — | — |
ToggleButtonProps
Import from @askrjs/ui/toggle.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
onPress | onPress?: ((e: PressEvent) => void) | undefined; | — | — |
pressed | pressed?: boolean | undefined; | — | — |
ref | ref?: Ref<HTMLButtonElement>; | — | — |
type | type?: "button" | "submit" | "reset" | undefined; | — | — |
ToggleOwnProps
Import from @askrjs/ui/toggle.
| Prop | Type | Default | Description |
|---|---|---|---|
children | children?: unknown; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
onPress | onPress?: ((e: PressEvent) => void) | undefined; | — | — |
pressed | pressed?: boolean | undefined; | — | — |
ToggleProps
Import from @askrjs/ui/toggle.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: boolean | undefined; | — | — |
children | children?: unknown; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
onPress | onPress?: ((e: PressEvent) => void) | undefined; | — | — |
pressed | pressed?: boolean | undefined; | — | — |
ref | ref?: ((value: Element | null) => void) | { current: Element | null; } | ((value: HTMLButtonElement | null) => void) | { current: HTMLButtonElement | null; } | null | undefined; | — | — |
type | type?: "button" | "submit" | "reset" | undefined; | — | — |
ToggleGroupItemAsChildProps
Import from @askrjs/ui/toggle-group.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild: true; | — | — |
children | children: JSXElement; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
onPress | onPress?: ((event: PressEvent) => void) | undefined; | — | — |
ref | ref?: Ref<Element>; | — | — |
type | type?: undefined; | — | — |
value | value: string; | — | — |
ToggleGroupItemOwnProps
Import from @askrjs/ui/toggle-group.
| Prop | Type | Default | Description |
|---|---|---|---|
children | children?: unknown; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
value | value: string; | — | — |
ToggleGroupItemProps
Import from @askrjs/ui/toggle-group.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
onPress | onPress?: ((event: PressEvent) => void) | undefined; | — | — |
ref | ref?: Ref<HTMLButtonElement>; | — | — |
type | type?: "button" | "submit" | "reset" | undefined; | — | — |
ToggleGroupMultipleProps
Import from @askrjs/ui/toggle-group.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | Supports literal, nested, array-mapped, and `For`-rendered descendants. |
defaultValue | defaultValue?: string[] | undefined; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
id | id?: string | undefined; | — | — |
loop | loop?: boolean | undefined; | — | — |
onValueChange | onValueChange?: ((value: string[]) => void) | undefined; | — | — |
orientation | orientation?: ToggleGroupOrientation | undefined; | — | — |
ref | ref?: Ref<HTMLDivElement>; | — | — |
type | type: "multiple"; | — | — |
value | value?: string[] | undefined; | — | — |
ToggleGroupProps
Import from @askrjs/ui/toggle-group.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | Supports literal, nested, array-mapped, and `For`-rendered descendants. |
defaultValue | defaultValue?: string | string[] | undefined; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
id | id?: string | undefined; | — | — |
loop | loop?: boolean | undefined; | — | — |
onValueChange | onValueChange?: ((value: string[]) => void) | ((value: string) => void) | undefined; | — | — |
orientation | orientation?: ToggleGroupOrientation | undefined; | — | — |
ref | ref?: Ref<HTMLDivElement>; | — | — |
type | type?: "single" | "multiple" | undefined; | — | — |
value | value?: string | string[] | undefined; | — | — |
ToggleGroupSingleProps
Import from @askrjs/ui/toggle-group.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | asChild?: false | undefined; | — | — |
children | children?: unknown; | — | Supports literal, nested, array-mapped, and `For`-rendered descendants. |
defaultValue | defaultValue?: string | undefined; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
id | id?: string | undefined; | — | — |
loop | loop?: boolean | undefined; | — | — |
onValueChange | onValueChange?: ((value: string) => void) | undefined; | — | — |
orientation | orientation?: ToggleGroupOrientation | undefined; | — | — |
ref | ref?: Ref<HTMLDivElement>; | — | — |
type | type?: "single" | undefined; | — | — |
value | value?: string | undefined; | — | — |
Purpose
This page covers two related but distinct primitives: `Toggle`, a single pressed/unpressed button (bold, italic, favorite-star patterns), and `ToggleGroup`, a set of toggle buttons where selecting one can affect the others — either a single-select group like alignment buttons or a multi-select group like text formatting. They share the same pressed-state model but solve different layout problems, which is why they're documented together rather than as a combined component.
Install and import
Both primitives ship from `@askrjs/ui` with their own subpaths — `@askrjs/ui/toggle` and `@askrjs/ui/toggle-group` — and matching `@askrjs/themes/toggle` and `@askrjs/themes/toggle-group` JS subpaths that re-export the same components; there's no separate `toggle.css` file, just `toggle-group.css` in the default theme covering both, loaded the same way as every other component's styling (via `@askrjs/themes/default`, not per-subpath). Import only the JS subpath you need; a page that just needs a single toggle button doesn't have to pull in the group's item-collection logic.
Live examples
The examples include a standalone `Toggle` for a single boolean action, a single-select `ToggleGroup` (`type="single"`) for mutually exclusive choices like text alignment, and a multi-select `ToggleGroup` (`type="multiple"`) for independent choices like bold/italic/underline stacked together.
Anatomy
`Toggle` is a standalone component with no required children structure beyond its own content. `ToggleGroup` is a root that wraps one or more `ToggleGroupItem` children, each identified by a required `value` string — the group reads its items' values to compute what's selected rather than you tracking indices.
State model
`Toggle`'s `pressed` prop is deliberately controlled-only — there's no `defaultPressed` or internal fallback, so you own the boolean and respond to `onPress`. `ToggleGroup` splits on its `type` discriminant: `type="single"` (the default) uses a string `value`/`defaultValue`/`onValueChange`, while `type="multiple"` switches all three to arrays of strings. Passing the wrong shape for the chosen `type` is a type error, not a runtime surprise.
Keyboard and accessibility
`Toggle` uses `role="button"` with `aria-pressed` and responds to both Enter and Space, and its types explicitly prohibit `onClick` in favor of `onPress` — the package's own docs note this is because `onClick` doesn't carry toggle or disabled semantics the way the pressable foundation's `onPress` does. `ToggleGroup` exposes a `loop` prop that controls whether arrow-key navigation wraps from the last item back to the first, and the group itself carries `role="group"` while each item keeps `role="button"` with `aria-pressed`.
Styling and tokens
Both components expose `data-state` (`on`/`off` for Toggle, similar semantics per item in a group) and `data-disabled` for CSS targeting, plus `data-orientation` on `ToggleGroup` so horizontal and vertical layouts can be styled independently. `@askrjs/themes` applies the shared button-like visual language here, so a themed `Toggle` looks consistent with `Button` at rest and simply adds a pressed treatment.
API
`Toggle` takes `pressed`, `onPress`, `disabled`, and the usual `asChild` escape hatch. `ToggleGroup` takes `type`, the value props matching that type, `orientation`, `loop`, and `disabled` (which cascades to disable the whole group); `ToggleGroupItem` takes its own `value`, optional `disabled`, and `asChild`, letting individual items opt out independently of the group-level flag.
Edge cases
Disabling `ToggleGroup` at the root disables every item regardless of each item's own `disabled` prop, but the reverse isn't true — you can disable individual items in an otherwise enabled group. Because `ToggleGroupItem`'s `value` is required, forgetting to set one is a compile-time error rather than something that silently breaks selection at runtime.
Related pages
For a single always-visible on/off control tied to a setting rather than a pressed visual, Switch is usually the better fit. If your toggle group is really acting as a segmented tab selector, look at Tabs instead — the visual overlap is common but the semantics differ.