Skip to content

Button group

A button group joins related .re-buttons into one control: the inner seams collapse to a single hairline and only the group’s outer corners stay rounded. It’s CSS-only — wrap the buttons in .re-button-group with role="group" and an accessible name.

Members must be direct .re-button children and share a uniform variant. Toggle members use native aria-pressed; disabled members use <button disabled> or, for links, <a class="re-button" aria-disabled="true">.

Live example
<div class="re-button-group" role="group" aria-label="Text formatting">
  <button class="re-button" data-variant="secondary" type="button">Bold</button>
  <button class="re-button" data-variant="secondary" type="button">Italic</button>
  <button class="re-button" data-variant="secondary" type="button" aria-pressed="true">
    Underline
  </button>
</div>

Add data-orientation="vertical" to stack the members; the collapse and corner rounding move to the block axis and align-items: stretch equalizes the widths.

Live example
<div class="re-button-group" data-orientation="vertical" role="group" aria-label="Alignment">
  <button class="re-button" data-variant="secondary" type="button">Left</button>
  <button class="re-button" data-variant="secondary" type="button">Center</button>
  <button class="re-button" data-variant="secondary" type="button">Right</button>
</div>

Any .re-button element works — including <a>. A disabled link uses aria-disabled="true" (it stays keyboard-focusable).

Live example
<div class="re-button-group" role="group" aria-label="Export">
  <a class="re-button" data-variant="secondary" href="#csv">CSV</a>
  <a class="re-button" data-variant="secondary" href="#json">JSON</a>
  <a class="re-button" data-variant="secondary" role="link" aria-disabled="true">PDF</a>
</div>
  • For a band of unrelated controls with arrow-key roving, use the Toolbar instead.
  • The group sets no overflow, so a focused member’s ring is never clipped; the focused member lifts above its neighbors via z-index.
  • Everything is logical-property based, so it mirrors correctly in RTL.
  • Keyboard — entirely native and per-member; the group adds no roving tabindex or arrow-key navigation. Tab/Shift+Tab moves through each member in order; Enter/Space activates a <button> member and Enter follows an <a> member. (If you want arrow-key roving across a band of controls, reach for the Toolbar instead.)
  • Focus — each member shows the standard visible :focus-visible ring (--re-shadow-focus); the group sets no overflow and lifts the focused member via z-index, so the ring is never clipped by a neighbor (see Notes above).
  • Semantics — the container is role="group" with an accessible name (aria-label), so assistive tech announces the members as one labelled cluster. Members keep their native roles (button, link). Toggle members carry native aria-pressed, announced as a pressed/not-pressed state. Disabled members use <button disabled> (removed from the tab order) or, for links, aria-disabled="true" (announced disabled but still focusable).
  • Notes — the join is purely visual: members stay independent focus stops, so the joined look never changes how the group is operated. See the accessibility guide for the project-wide baseline.