Skip to main content

Design system components

ButtonGroup

Groups related Buttons into one attached (segmented) or spaced row.

Status: beta. Group: actions. Markdown version: /design-system/components/button-group.md

When to use

ButtonGroup presents sibling actions as one surface. Attached (default) collapses inner radii and shares 1px seams for view switchers and compact toolbars; attached=false keeps the group semantics but spaces the buttons for form action rows. Children should share variant and size. It groups independent actions; it does not manage selection state.

When not to use

  • Do not use it for exclusive selection (active segment state); that is a toggle-group pattern this component deliberately does not implement.

Look-alikes

  • SegmentedControl: Do not use it for actions or navigation that commits/routes; use ButtonGroup or links. Selecting must only change the bound value.
  • SplitButton: Do not put a menu trigger inside; SplitButton owns primary-action + menu.

Props

ButtonGroup props
PropTypeDefaultDescriptionRequired
ariaLabelstringnoneAccessible name for the group (announced by screen readers).No
attachedbooleantrueFuse the children into one segmented control surface.No
childrenReact.ReactNodenoneButtons / IconButtons of the same variant and size.Yes

Variants

No variant dimensions and no props with a fixed set of values.

Invalid combinations

The contract records no invalid combinations.

Keyboard

ButtonGroup keyboard behaviour
KeyBehaviour
TabMoves through each child button (no roving tabindex)

Rules

Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.

ButtonGroup rules
LevelRuleHow it is checked
MUSTARIA: Role=group with aria-label naming the cluster.Not yet verified: no evidence record. WCAG 4.1.2.
MUSTRequired stories produce no axe violations at the configured severity.Automated by npm run test:stories:matrix:ci. WCAG 2.5.8.
MUSTThe accessibility tree (role, name, state) matches the committed snapshot for every required story.Automated by npm run test:stories:matrix:ci. WCAG 1.3.1, 4.1.2.
MUSTThe component remains legible and operable under a real browser forced-colors: active pass.Automated by npm run test:stories:hc.
MUSTEvery documented keyboard interaction works as specified.Not yet verified: no evidence record. WCAG 2.1.1, 2.1.2.
MUSTA human completed an end-to-end accessibility review of this component.Manual review, last on 2026-07-03.
SHOULDUse one variant and one size for every segment; mixed weights read as unrelated buttons touching.Not stated in the contract.
SHOULDName the group with ariaLabel ("Text alignment", "View") so AT users get the context first.Not stated in the contract.
SHOULDPrefer secondary variant for attached segments; the outline makes the shared seams legible.Not stated in the contract.
SHOULDUse IconButtons for compact toolbar clusters; each still needs its own label.Not stated in the contract.
SHOULD NOTDo not put a menu trigger inside; SplitButton owns primary-action + menu.Not stated in the contract.

Install and import

  • Install: npm install @digitaltableteur/react (version 0.9.1, restricted access on npm).
  • Import: import { ButtonGroup } from "@digitaltableteur/react";
  • Entry point: @digitaltableteur/react/actions exports it too.
  • Styles: import @digitaltableteur/react/style.css once at the app boundary.
  • Also available as the custom element <dt-button-group>; see the custom elements manifest.