skrewww

Actions

Button Group

Button Group joins related independent Buttons with shared outer chrome and a 2px divider gap — layout only; each Button keeps its own behavior.

Style × Count (2/3/4) — 9 Figma variants; React uses children + divider chrome

betaReact AvailableFigma AvailableDocs Partial
React last updated
2026-09-13
Documentation last updated
2026-09-13
Accessibility target
WCAG 2.2 AA (target)
Version
0.1.0-beta

Known open questions

  • Figma description recommends role=radiogroup for mutually exclusive selection; Beta React ships independent Buttons with role=group (CE-1B product decision). Use Toggle Group for exclusive selection.
  • Vertical orientation, equal-width, and wrapping are not in the verified Figma set.
  • Squircle Shape on joined children disables per-button squircle clip so shared outer chrome stays coherent.

Live preview

Joined Button composition — each child remains an independent Button. Divider chrome matches Figma Style gap fills.

Surface
Shape

Primary (divider=primary)

Secondary (divider=neutral)

Danger (divider=danger)

Mixed disabled child

Purpose

Button Group joins related independent Buttons with shared outer border and a 2px divider gap — visual grouping only.

Anatomy

ButtonGroup = role=group wrapper (shared border + divider gap + outer radius) + Button children. Divider tone is group chrome only.

Variants and states

neutral · primary · danger

When to use

When 2–4 related actions should read as one joined unit (for example List/Grid view triggers or compact action clusters).

When not to use

For mutually exclusive selection/state — use Toggle Group (segmented exclusive selection). For one primary action plus a related menu — use Split Button. For unrelated actions, keep separate Buttons.

Accessibility

Renders as role="group" with optional aria-label. Each child remains an independent Button (Tab / Enter / Space). Not role=radiogroup — does not implement selection.

Keyboard behavior

Standard Tab order across child Buttons. Enter/Space activate the focused Button. No arrow-key roving focus — this is not a toolbar or radiogroup.

Common mistakes

Giving each segment its own outer border (double seams). Putting Button variant/size/loading on the group. Treating the group as a segmented control with selection state — use Toggle Group instead.

Properties

Figma: Style × Count. React: children (Buttons) + divider (neutral|primary|danger) for gap chrome. Count is not a React prop.

How is Button Group different from Split Button?

Button Group arranges multiple independent actions with joined chrome. Split Button pairs one primary default action with a related secondary/menu control — not Button Group.

Is Button Group a segmented control?

No. Figma labels can look like List/Grid or Day/Week/Month, but Button Group does not implement selection state. Use Toggle Group for exclusive segmented selection (Segmented Control is that presentation, not a separate component).

Tokens used

component/radius/controlsemantic/border/defaultcolor/brand/700color/danger/700

Known limitation

Figma prose describes mutually exclusive segments; React ships independent actions (CE-1B). Use Toggle Group for exclusive selection. Vertical orientation, equal-width, and wrapping are not verified in Figma.

Component API

PropTypeDefaultDescription
childrenReactNodeIndependent Skrewww Button (or Button-as-link) children.
divider"neutral" | "primary" | "danger""neutral"Chrome color in the 2px gap — matches Figma Style gap fill (neutral=Secondary, primary, danger). Not a Button variant.
aria-labelstringAccessible name for the group when no visible group label exists.
aria-labelledbystringID of a visible label element for the group.

React example

Copy React example
import { Button } from "@/components/ui/Button";
import { ButtonGroup } from "@/components/ui/ButtonGroup";

export function Example() {
  return (
    <ButtonGroup aria-label="View mode" divider="primary">
      <Button variant="primary">List</Button>
      <Button variant="primary">Grid</Button>
    </ButtonGroup>
  );
}