Persona

Button Group

Actions · 3 props · Updated Sep 22, 2026

Button Group is a row of icon buttons that acts as one control. One prop decides whether choosing is exclusive, and the group reports a value rather than clicks.

  • Group container holds the buttons and decides how choosing works: type="single" makes them radios, type="multiple" makes them checkboxes.
  • Button one option, and always an icon button — items are 32x32 whatever you put in them. Selected is a filled ground, not an outline.

Use a button group when a few options do one job and each of them can be named by an icon: text alignment, bold and italic, a chart’s time range.

Items are icon buttons fixed at 32x32, so words do not fit — a text label overflows the square rather than widening it. If the options need words then this is not the control. Use Radio for one choice among a few and Checkbox for several, both of which read their options down a column; use Select once the list is long enough to be worth closing. Tab Bar swaps the content region, where a button group changes a value on the page you are already on.

fullWidth stretches the group to its container and splits the space evenly between the items. It is the only thing that changes their width.

Button Group throws without a selection type

Section titled “Button Group throws without a selection type”

type has no default and the component throws without it. type="single" holds one value; type="multiple" holds an array and lets every item be on at once. Each item carries a value, and those values are what value, defaultValue and onValueChange deal in.

Clicking the selected item switches it off, and the group’s value becomes the empty string. A radio group has no way to do that, so code carried over from one will not be expecting it. Where the control must always hold a selection, own value and drop the change that would clear it.

Every item needs its own label, and so does the group

Section titled “Every item needs its own label, and so does the group”

An item is an icon button with no text, so its accessible name has to come from aria-label. Without one it reaches a screen reader as an unnamed radio or toggle, which in a row of three unnamed items is unusable rather than merely terse. Name the group as well, with aria-labelledby pointing at the label above it.

The roles are not yours to set. type="single" renders role="radiogroup" on the group and role="radio" with aria-checked on each item; type="multiple" renders role="toolbar" and aria-pressed. Writing them by hand overrides state the group is already keeping.

Tab moves to the group, not into it: focus lands on the selected item, the arrow keys move between items and wrap at both ends, and the next Tab leaves the group entirely. So a keyboard user passes a five-item group in one keystroke, and the selected item is the one they meet if they stop.

Nest the group in a form field for helper text and errors

Section titled “Nest the group in a form field for helper text and errors”

Inside a FormField the group reads that field: a disabled field disables every item, and the field’s helper text becomes the group’s aria-describedby. An invalid field marks the group aria-invalid too, so the error is announced once, from the field, rather than repeated per item.

type is required, and it is missing from this table: it comes from the Radix toggle group the component is built on rather than from ButtonGroup’s own props, and the generator only reads the latter.

NameType
id

string

className

string

fullWidth

boolean

Was this page helpful?