Toggle Group
A set of joined toggle buttons sharing one selection — single or multiple selection, three sizes, horizontal or vertical layout, full keyboard navigation.
- Status
- Since
0.1.0- Accessibility pattern
- APG toolbar of toggle buttons
Last updated
Install
Add Toggle Group from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.
pnpm dlx shadcn@latest add @vegastack/toggle-groupThe same command installs the registry items it composes: @vegastack/toggle.
Usage
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
<ToggleGroup defaultValue={["bold"]} aria-label="Text formatting">
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
<ToggleGroupItem value="italic">Italic</ToggleGroupItem>
<ToggleGroupItem value="underline">Underline</ToggleGroupItem>
</ToggleGroup>;Anatomy
Toggle Group is a compound component. Every exported part, with the
data-slot it renders (generated from the canonical source):
Examples
Anatomy
ToggleGroup is a compound component built on Base UI Toggle Group. Compose the items inside the
root; its visible outer hairline keeps the joined options legible at rest, while size set once on
the root flows to every item via context. Selection is an
array of item values:
<ToggleGroup defaultValue={["center"]} orientation="horizontal">
<ToggleGroupItem value="left">
<Icon />
</ToggleGroupItem>
<ToggleGroupItem value="center">
<Icon />
</ToggleGroupItem>
<ToggleGroupItem value="right">
<Icon />
</ToggleGroupItem>
</ToggleGroup>ToggleGroup— the root that owns the shared selection andorientation(data-slot="toggle-group",data-size,data-orientation,data-multiplewhen multi-select). Controlled viavalue/onValueChange(an array of pressed values), or uncontrolled viadefaultValue. Passmultipleto allow more than one item pressed at a time.ToggleGroupItem— a single toggle button (data-slot="toggle-group-item"). Identify it withvalue; pressed state is exposed asdata-pressedand announced viaaria-pressed. Inherits the group'ssizefrom context unless overridden. The first and last items round the group's outer corners so the buttons read as one joined control.
Selection
By default a Toggle Group is single-select — pressing an item unpresses the others, like a radio group. The selected value is the first (and only) entry in the array.
Pass multiple for multiple selection — each item presses independently, like a set of
checkboxes. Common for formatting toolbars where bold, italic, and underline can all be active at once.
Sizes
size (sm / default / lg) is set once on the root and flows to every item. Items render flush
inside one visible border-border boundary with shared rounded ends, so the group reads as a single
control even when nothing is selected; the pressed item takes the same evident neutral fill as a
standalone Toggle.
<ToggleGroup size="lg" aria-label="Text alignment">
<ToggleGroupItem value="left">
<AlignLeft />
</ToggleGroupItem>
<ToggleGroupItem value="center">
<AlignCenter />
</ToggleGroupItem>
<ToggleGroupItem value="right">
<AlignRight />
</ToggleGroupItem>
</ToggleGroup>Orientation
Set orientation="vertical" on the root to stack the items into a column — the joined corners round
the top of the first item and the bottom of the last. Keyboard navigation switches to the up/down
arrow keys automatically.
<ToggleGroup orientation="vertical" aria-label="View">
<ToggleGroupItem value="list">List</ToggleGroupItem>
<ToggleGroupItem value="grid">Grid</ToggleGroupItem>
</ToggleGroup>States
Pass disabled on the root to disable the whole group — it flows to every item, dims the group via
disabled:opacity-(--opacity-dim), and skips it for pointer and keyboard interaction. (A single item can be
disabled the same way — see the Selection example above.)
Playground
Try both orientations, the three sizes, and single vs multiple selection, then copy the generated JSX.
<ToggleGroup aria-label="Text alignment">
<ToggleGroupItem value="left" aria-label="Align left">
<AlignLeft />
</ToggleGroupItem>
<ToggleGroupItem value="center" aria-label="Align center">
<AlignCenter />
</ToggleGroupItem>
<ToggleGroupItem value="right" aria-label="Align right">
<AlignRight />
</ToggleGroupItem>
</ToggleGroup>API Reference
ToggleGroup
| Prop | Type | Default | Description |
|---|---|---|---|
defaultValue | readonly string[] | — | The initially pressed items as an array of their values. Uncontrolled
counterpart of value. |
multiple | boolean | false | Allow multiple items to be pressed at once. When false, pressing an item
unpresses the others (single-select, radio-like). |
onValueChange | ((value: string[]) => void) | — | Fired when the pressed items change, with the next array of pressed values. |
orientation | "horizontal" | "vertical" | 'horizontal' | Layout flow. horizontal joins items left-to-right; vertical stacks them.
Also drives the arrow-key axis for keyboard navigation. |
size | "lg" | "md" | "sm" | 'md' | Control height/density applied to every item — mirrors the Button scale. |
value | readonly string[] | — | The pressed items as an array of their values. Controlled counterpart of
defaultValue — pair with onValueChange. In single-select mode the array
holds at most one value. |
Data attributes and CSS variables on ToggleGroup
| Attribute | Values |
|---|---|
data-size | "md" |
data-slot | "toggle-group" |
ToggleGroupItem
| Prop | Type | Default | Description |
|---|---|---|---|
size | "lg" | "md" | "sm" | 'md' | Control height/density. Defaults to the group's size (set via context); set
here only to override a single item. |
Data attributes and CSS variables on ToggleGroupItem
| Attribute | Values |
|---|---|
data-size | mirrors a prop or state value |
data-slot | "toggle-group-item" |
Accessibility
- Built on Base UI Toggle Group: each item renders as a
<button>witharia-pressedreflecting its state; the pressed state is also exposed asdata-pressedfor styling. - Always pass an
aria-label(oraria-labelledby) to the group so assistive tech announces its purpose — icon-only items should each carry their ownaria-labeltoo. - Roving tabindex — the group is a single tab stop; arrow keys move focus between items and wrap
around (
loopFocus, on by default). - Items carry no custom ring class and never set
outline: none, so keyboard focus shows the design system's global 2px:focus-visiblering (outline-ring). On focus an item raises its stacking order (focus-visible:z-10) so that ring is painted on top and never clipped by the adjacent joined buttons. - A disabled group (or item) sets
disabledon the underlying button, is skipped by pointer and keyboard interaction, and is dimmed viadisabled:opacity-(--opacity-dim).
| Key | Action |
|---|---|
| Tab | Move focus into the group (lands on the first or pressed item), then out. |
| ← / → | Move focus between items (horizontal orientation). |
| ↑ / ↓ | Move focus between items (vertical orientation). |
| Home / End | Move focus to the first / last item. |
| Enter / Space | Toggle the focused item. |
| Contract | States tested |
|---|---|
| Behaviour | default, pressed |
| Accessibility | focus-visible, labeled |
| Visual | default, focus |