C-02 · Components · Actions
All elements · ButtonGroup on the Components page
Last checked 2026-10-22 · Awaiting approval · Accessibility tests
Approve ButtonGroup
Approving as
Guidance
When to use
- Use a button group to show two to five related buttons as one set, such as Day, Week, Month.
-
Use
data-selection="single"to switch between views of the same data, such as list, table, cards and kanban. -
Use
data-selection="multiple"for independent formatting states, such as Bold, Italic and Underline. -
Use
data-attachedordata-variant="segmented"when the buttons should read as one control.
When to consider something else
- If the buttons switch panels of different content, use tabs. See Tabs.
- If there are many commands in several groups, use a toolbar with roving focus. See Toolbar.
- If the choice is a form value rather than a view, use radio toggles or a select. See Toggle.
- If one main action has close variants, use a split button. See SplitButton.
Usability
- Keep the buttons the same size and variant inside one group.
- Give every icon-only button a name and a tooltip; view icons alone are hard to tell apart.
- In a single-selection group, always keep one button pressed.
-
Name the group with
aria-labeloraria-labelledbyso the set has a purpose.
- Don't mix actions and state toggles in one group.
- Don't put more than about five buttons in a group; use a select or menu instead.
- Don't show the pressed state with color alone; the pressed style also changes the border and background.
Accessibility
Keyboard
| Keys | Action |
|---|---|
| Tab | Moves focus to the next button in the group, then out of the group. |
| Shift+Tab | Moves focus to the previous button. |
| Enter or Space |
Activates the focused button. With data-selection="single" it presses that button
and releases the others; with multiple it flips only that button.
|
Roles and names
- The container is
role="group"with an accessible name. -
Each button is a native
<button>; selectable buttons carryaria-pressed="true|false". -
Icon-only buttons need
aria-label; letter glyphs such as B, I and U still need a full name like "Bold".
Focus
- Each button is its own tab stop in the static layer. If the group sits inside a toolbar, the toolbar's roving focus takes over and the group is one stop.
-
The focus ring must stay visible over the joined borders of an attached group; the pressed button is
raised with
z-indexso its border shows.
Other requirements
-
Target size 2.5.8: attached
smicon buttons share edges; the a11y report records a 22px spacing failure in the classic skin, so usemdor add a gap where touch use is likely. - The pressed state must reach 3:1 against the unpressed state and the background (1.4.11).
-
State is exposed through
aria-pressed, so screen readers announce it without extra text (4.1.2).
Test your implementation too. This guidance covers the element as specified here. How a screen composes it (labels, order, announcements) still needs its own keyboard and screen reader check.
Accessibility tests
Passed the gate (run 358b316 on 2026-10-22): no finding in any theme. Awaiting a person’s approval of the checklist below.
| Area | Automated | A person checks |
|---|---|---|
| General | Passed | Color is never the only cue, text alternatives say the same thing as the graphic, and the element reads the same in the light and the dark theme. |
| Zoom | Passed | At 200% zoom, at 320 CSS pixels wide and with the WCAG text-spacing overrides, nothing is lost, clipped or overlapping. |
| Keyboard | Passed | Every row of the Keyboard table works, focus is always visible and never trapped, and the tab order follows the reading order. (3 rows) |
| Screen reader | Passed | With NVDA or JAWS on Windows and VoiceOver on macOS, names, roles and states are announced as Roles and names says, and changes are announced once. (3 items) |
Approving. When the checklist passes on the checked run, record it with
bun run a11y:approve -- button-group --by "Your name" and commit
a11y/approvals.json with the rebuilt pages.
All test status
Package
Consumers link one stylesheet, css/classic/index.css, which includes every element. The
files below are where this element is defined.
Latest updates
No recorded changes yet.