Toggle
One control that stays pressed: bookmark, pin, mute, unread only. The single-item sibling of Toggle Group, sharing its paint and its heights, with a pressed glyph that fills in instead of blinking.
Installation#
Usage#
import { Toggle } from "@/components/ui/toggle"
export function Example() {
return <Toggle aria-label="Show grid">Show grid</Toggle>
}Anatomy#
import { Toggle, ToggleIcon } from "@/components/ui/toggle"
<Toggle>
<ToggleIcon off={…} on={…} />
</Toggle>Variants#
outline (the default) is the Toggle Group pill: a framed control whose pressed state is an ink border and a soft halo, with no fill. ghost is bare at rest and takes the accent chip once pressed, the Toolbar's pressed look, for icon toggles in a row of other controls. Each is shown off, then on.
Sizes#
The Toggle Group scale: sm is 32px and md (the default) is 40px, so a lone toggle lines up with a group beside it. iconOnly squares the control around one glyph and steps the glyph up to 20px at md. The 32px control grows its target to 40px (44px on touch) without growing the visual.
Pressed glyph#
ToggleIcon holds two glyphs in one cell and cross-fades them on the toggle's state: the outgoing one shrinks to a quarter, fades and blurs as the incoming one resolves, on a CSS transition, so pressing twice quickly reverses mid-way instead of restarting. Pass the pressed glyph in its fill weight, which is how the system marks a selected state, or a different glyph when on means something else (a slashed microphone). Press them.
With a tooltip#
An icon-only toggle is named by its aria-label: the glyph is not a name. Show that name to sighted users with a Tooltip, and wrap the row in a TooltipGroup so the bubble glides from one toggle to the next.
Controlled#
Hold the state yourself with pressed and onPressedChange. Here it filters the list under it; the count is tabular-nums, so it never jitters as it changes.
Disabled#
disabled dims the control in either state and takes it out of the pointer's way, so a locked setting still shows which way it is set.
API reference#
Toggle
A <button> that stays pressed, with aria-pressed. Forwards all Radix Toggle Root props; every part accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "outline" | "ghost" | "outline" | outline is the Toggle Group pill (ink border and halo when pressed); ghost is bare and fills with the accent chip. |
| size | "sm" | "md" | "md" | 32px or 40px tall; sm grows its hit target to 40px without growing the visual. |
| iconOnly | boolean | false | Squares the control around one glyph (20px at md). Name it with aria-label. |
| pressed | boolean | - | The controlled pressed state. |
| defaultPressed | boolean | false | The initial pressed state when uncontrolled. |
| onPressedChange | (pressed: boolean) => void | - | Called when the pressed state changes. |
| disabled | boolean | false | Dims the control in either state and blocks interaction. |
| asChild | boolean | false | Renders onto its child element instead of a <button>. |
| Data attribute | Description |
|---|---|
| data-state | "on" while pressed, "off" otherwise. |
| data-disabled | Present when the toggle is disabled. |
ToggleIcon
Two glyphs in one cell that cross-fade on the surrounding Toggle's state; decorative (aria-hidden), so it only works inside a Toggle. Forwards all native <span> props except children.
| Prop | Type | Default | Description |
|---|---|---|---|
| off* | React.ReactNode | - | The glyph at rest. |
| on* | React.ReactNode | - | The glyph while pressed, usually the same icon in its fill weight. |