ButtonGroup
Preview appears after the next Storybook update.
<ButtonGroup />When to use
Use it for
- Footers of dialogs, forms and cards: primary at the end, alternatives before it.
- Attached: two to five closely related choices of equal weight, like Unified or Split diff.
Not for
- Switching between views of content: use Tabs, which manage the panel and arrow-key navigation.
- A single choice that persists as a setting: use RadioGroup.
Do and don't
Every example is rendered with the real component, so it always matches what ships.
Put the primary action last
Users read the alternatives on the way to the main action, and the primary lands where the eye ends.
Mix variants in an attached group
An attached group reads as one control. Mixed fills break it into unrelated pieces.
Accessibility
- Renders role="group". Pass aria-label when the buttons are related choices so the group is announced.
- Each button stays in the tab order; the focused button lifts above its neighbors so the ring is never clipped.
- Vertical groups stack the same buttons; the tab order follows the visual order.
Content guidelines
- Labels in one group share a grammatical form: all verbs, or all nouns for view choices.
- Keep attached groups to five items or fewer.
From the code Generated from the component, not editable here.
Anatomy and tokens
Read from packages/react/src/components/ButtonGroup/ButtonGroup.module.css at build time. Every value is a token: open one to see its alias chain in both themes.
- Spaced appearance (gap between buttons)
.spaced - Attached appearance (segmented)
.attached.horizontal > *:not(:first-child) - Attached appearance (segmented)
.attached.vertical > *:not(:first-child)
Motion and interaction
ButtonGroup does not animate: it only lays out other components.
From the code Generated from the component, not editable here.
Props
Parsed from the TypeScript types in packages/react/src/components/ButtonGroup/ButtonGroup.tsx, so this table cannot drift from the code. It also accepts every native <div> attribute.
| Prop | Type | Default | Description |
|---|---|---|---|
appearance | 'spaced' | 'attached' | 'spaced' | Accessible name for the group, for example "Text alignment". Required when the buttons are related choices. */ 'aria-label'?: string; /** `attached` joins the buttons into one segmented control; `spaced` keeps a gap (action bars). Default `spaced`. |
orientation | 'horizontal' | 'vertical' | 'horizontal' | No description in the code yet. |
align | 'start' | 'end' | 'between' | 'start' | Align the group's buttons. Default `start`. Use `end` for dialog and form footers. |
Playground
Change the props and see the real ButtonGroup update. Controls are generated from the TypeScript props; nothing here changes the system.
<ButtonGroup align="end" aria-label="Review actions" />Workbench
For contributors: every state with the accessibility panel, in the component workbench (Storybook). The stories double as visual test fixtures; the guidance on this page is the user documentation (open ButtonGroup in Storybook).
Embed Storybook stories here (3)
Loads from https://bridge-storybook.floriangouloubi.com (set STORYBOOK_URL at build time). If Storybook is not running, the frames stay empty.
Footer
Attached
AllStates
From the code Generated from the component, not editable here.
Changelog
- Fix
ButtonGroup: the focus rule of attached groups uses
> :focus-visible, same behaviour, no universal selectorv1.0.0, Nov 11, 2026