toggle group
A set of two-state buttons that can be toggled on or off.
Philosophy
When multiple toggles share context, they become a group. ToggleGroup manages mutual exclusivity (single mode) or multi-selection, keeping the state logic out of your components. Built on @gentleduck/primitives/toggle-group with roving focus keyboard navigation — arrow keys move between items, Space/Enter toggles them.
How It's Built
Installation
npx @gentleduck/cli add toggle-group
npx @gentleduck/cli add toggle-group
Usage
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'<ToggleGroup type="single">
<ToggleGroupItem value="a">A</ToggleGroupItem>
<ToggleGroupItem value="b">B</ToggleGroupItem>
<ToggleGroupItem value="c">C</ToggleGroupItem>
</ToggleGroup><ToggleGroup type="single">
<ToggleGroupItem value="a">A</ToggleGroupItem>
<ToggleGroupItem value="b">B</ToggleGroupItem>
<ToggleGroupItem value="c">C</ToggleGroupItem>
</ToggleGroup>Examples
Default
Outline
Single
Small
Large
Disabled
Keyboard Navigation
| Key | Description |
|---|---|
Tab | Moves focus into the toggle group (focuses the active or first item) |
ArrowRight | Moves focus to the next item |
ArrowLeft | Moves focus to the previous item |
ArrowDown | Moves focus to the next item |
ArrowUp | Moves focus to the previous item |
Home | Moves focus to the first item |
End | Moves focus to the last item |
Space / Enter | Toggles the focused item |
API Reference
ToggleGroup
| Prop | Type | Default | Description |
|---|---|---|---|
type | 'single' | 'multiple' | (required) | Determines selection behavior. 'single' allows one toggle at a time; 'multiple' allows multiple |
value | string | string[] | -- | Controlled selected value(s) |
defaultValue | string | string[] | -- | Uncontrolled initial selected value(s) |
onValueChange | (value: string | string[]) => void | -- | Callback invoked when the value changes |
variant | 'default' | 'outline' | 'default' | Visual style variant for the toggles (passed to items via context) |
size | 'default' | 'sm' | 'lg' | 'default' | Size variant for the toggles (passed to items via context) |
disabled | boolean | false | Disables all items in the group |
rovingFocus | boolean | true | Whether to use roving focus for keyboard navigation |
loop | boolean | true | Whether keyboard navigation should loop at boundaries |
orientation | 'horizontal' | 'vertical' | -- | The orientation of the group for arrow key navigation |
dir | 'ltr' | 'rtl' | -- | Text direction. Resolved by primitives useDirection (dir prop -> DirectionProvider -> 'ltr'). |
className | string | -- | Additional CSS class names to apply |
children | React.ReactNode | -- | ToggleGroupItem elements to render inside the group |
ref | React.Ref<HTMLDivElement> | -- | Ref forwarded to the underlying div element |
ToggleGroupItem
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | (required) | The unique value identifying this toggle item |
variant | 'default' | 'outline' | -- | Visual style variant for this item (overrides group context) |
size | 'default' | 'sm' | 'lg' | -- | Size variant for this item (overrides group context) |
disabled | boolean | false | Disables this specific item |
className | string | -- | Additional CSS class names to apply |
children | React.ReactNode | -- | Content rendered inside the toggle item |
ref | React.Ref<HTMLButtonElement> | -- | Ref forwarded to the underlying button element |
Data Attributes
| Attribute | Values | Description |
|---|---|---|
data-state | "on" | "off" | The pressed state of the item |
data-disabled | Present when disabled | Whether the item is disabled |
RTL Support
Set dir="rtl" on ToggleGroup for a local override, or set DirectionProvider once at app/root level for global direction.