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/themes/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/themes/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/themes/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/themes/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/themes/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/themes/toggle-group.
| Prop | Type | Default | Description |
|---|---|---|---|
children | children?: unknown; | — | — |
disabled | disabled?: boolean | undefined; | — | — |
value | value: string; | — | — |
ToggleGroupItemProps
Import from @askrjs/themes/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/themes/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/themes/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/themes/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.