Toggle
A two-state button — standalone for toolbar actions, or clustered as Toggle.Group for radiogroup-style choices.
At a glance
- A single bistable button — think of the B / I / U buttons in a rich-text toolbar.
- Cluster several with
<Toggle.Group>for shared selection semantics (toolbar-multiple, alignment-single). - ARIA:
role="button"+aria-pressedper item.<Toggle.Group>addsrole="group"(multiple) orrole="radiogroup"(single).
Toggle vs Switch vs Checkbox vs SegmentedControl
These four controls look similar but ship different semantics — pick the one that matches the meaning of the choice, not the shape of the visual.
- Toggle — a button with on/off state. Use it for toolbar-style actions (Bold, Pin, Mute). Lives outside
<form>. - Toggle.Group (
type="single") — a cluster where one or none can be active. Re-clicking the active item clears it. Use this when "no selection" is a valid state. - SegmentedControl — exactly one is always active. Use when "no selection" isn't a valid state.
- Switch — a setting that takes effect immediately ("Dark mode", "Email notifications"). Reads as
role="switch". - Checkbox — a value selected as part of a form. Reads as
role="checkbox".
Standalone Toggle
pressed and defaultPressed
Controlled mode: pass pressed and pair with onChange. Uncontrolled
mode: pass defaultPressed and let the Toggle track state.
variant
Visual treatment of the toggle when off and on.
| Value | Off state | On state |
|---|---|---|
default (default) | Subtle border + bg | Tinted background + accent border |
outline | 1px border, no fill | Tinted background + accent border |
size
Density. Aligned with Button's scale.
| Value | Min height |
|---|---|
sm | 32 px |
md (default) | 36 px |
lg | 44 px |
disabled
Greys the toggle out and blocks press handling. Forwarded as
aria-disabled.
aria-label / accessibilityLabel
When the visible content is just an icon, pass aria-label (web) or
accessibilityLabel (native) so screen readers say something
meaningful.
<Toggle.Group>
Clusters several Toggle items with shared selection semantics.
Roving-tabindex keyboard nav follows the WAI-ARIA radiogroup pattern:
arrow keys move focus, Home / End jump to the ends, Space /
Enter toggles the focused item. Default-variant grouped items share
borders so the cluster reads as one segmented chip — first item rounds
the left, last rounds the right.
type — multiple vs single
The shape of value follows from type:
type | value type | Re-click behavior |
|---|---|---|
multiple | string[] | Toggles the item in / out of the array |
single | string | undefined | Re-clicking the active item clears it |
Multiple selection (formatting toolbar)
type="multiple" — value is string[]. Clicking adds or removes an
item from the array.
Single selection (alignment)
type="single" — value is string | undefined. Clicking sets it;
clicking the active item again clears it.
value and defaultValue
Controlled (value + onChange) vs uncontrolled (defaultValue).
Their shapes follow type.
onChange
Fires with the next value whenever the user toggles an item. Pair
with value for controlled, omit for uncontrolled.
disabled
Disables every item in the group. Individual items can still set
their own disabled.
variant and size (group-level)
Forwarded to every item by default — set the cluster's look once and
items inherit. Per-item variant / size overrides the group value.
aria-label / accessibilityLabel
The group's accessible name. Required for assistive tech to announce
the cluster ("Text formatting, group"). For icon-only items inside,
give each item its own aria-label too.
Props
<Toggle>
| Prop | Type | Default | Description |
|---|---|---|---|
accessibilityLabel | string | — | — |
aria-label | string | — | Required when `children` is icon-only. |
children | ReactNode | — | Visible label or icon content. |
className | string | — | — |
defaultPressed | boolean | false | Uncontrolled initial pressed state. Ignored when `pressed` is provided. |
disabled | boolean | false | Group-level disable (also forwarded by `<ToggleGroup>` to its items). |
onChange | (next: boolean) => void | — | Fires with the next pressed state when the user toggles. |
pressed | boolean | — | Controlled pressed state. Pair with `onChange`. |
size | enum | md | @defaultValue 'md' |
testID | string | — | — |
variant | enum | default | Visual treatment. - `default` — transparent when off, filled with `interactive.primary` when on. - `outline` — bordered when off, tinted background + accent border when on. @defaultValue 'default' |
<Toggle.Group>
| Prop | Type | Default | Description |
|---|---|---|---|
type* | enum | — | Multi-select gives an array; single-select gives a string (or undefined). |
accessibilityLabel | string | — | — |
aria-label | string | — | — |
className | string | — | — |
defaultValue | string | string[] | — | — |
disabled | boolean | false | Group-level disable. Each item's `disabled` is OR-ed with this. |
onChange | ((next: string) => void) | ((next: string[]) => void) | — | — |
size | enum | md | @defaultValue 'md' |
testID | string | — | — |
value | string | string[] | — | — |
variant | enum | default | @defaultValue 'default' |
<Toggle.Item>
| Prop | Type | Default | Description |
|---|---|---|---|
value* | string | — | Unique identifier within the group — written into `value` when pressed. |
accessibilityLabel | string | — | — |
aria-label | string | — | — |
className | string | — | — |
disabled | boolean | false | Disable just this item (OR-ed with group-level `disabled`). |
testID | string | — | — |