Cmpnts

Menu

Molecules

Button Group

A set of related Buttons laid out together, in a row or a column.


Code
HTML
<div class="button-group">
  <button type="button" class="button"><span>Cancel</span></button>
  <button type="button" class="button button--strong button--accent"><span>Save</span></button>
</div>

Why it exists

Buttons that belong together should look as if they do. A Button Group keeps them at the right distance and lets them wrap when the space runs out. It lays them out and leaves them alone, so a Button looks and behaves the same in a group as anywhere else.

It has no alignment options, because where a group sits is the page’s decision. A justify-* utility or the layout around it makes that decision, and looks and sizes come from the Buttons, set for the whole group with .buttons-*.

Joined turns several Buttons into one control, and the hard part is left to the browser: an exclusive choice uses real radio inputs, so selection and arrow keys need no script. It won’t call itself a toolbar, because role="toolbar" promises arrow keys between controls and the library ships no script to keep that promise.

When to use

  • For a few related Buttons: a Form’s actions, a choice of views, text style toggles.
  • Not for rows of actions with headings and shortcuts: that is a Menu.
  • Not for actions on selected items: that is Batch Actions.
  • Not for moving between views of one thing, each with its own panel: that is Tabs.

Rules

  • Roles. A group whose Buttons share a purpose takes role="group" and a label. Not role="toolbar": a toolbar promises arrow keys between its controls, and the library ships no script.
  • Joined choices. Exclusive choices are radio inputs inside the Buttons, so the browser handles selection and arrow keys. Toggles are Buttons with aria-pressed. A joined group keeps every border; the hovered, selected or focused Button rises so its border and focus ring show in full.

Keyboard and screen readers

The browser provides all of this. Script only what a Button does, including flipping aria-pressed on a toggle.

  • Tab moves between Buttons, each its own stop. A set of radios is one stop.
  • Enter and Space press a Button.
  • Arrow keys move between radios and select as they go. They do nothing between ordinary Buttons.
  • A screen reader hears the label on entering a role="group" or role="radiogroup", then “pressed” from aria-pressed or the radio’s checked state.

Choosing one of several

Code
HTML
<div class="button-group button-group--joined" role="radiogroup" aria-label="Range">
  <label class="button"><input type="radio" name="range" value="day" class="sr-only" checked><span>Day</span></label>
  <label class="button"><input type="radio" name="range" value="week" class="sr-only"><span>Week</span></label>
  <label class="button"><input type="radio" name="range" value="month" class="sr-only"><span>Month</span></label>
</div>

Turning things on and off

Code
HTML
<div class="button-group button-group--joined" role="group" aria-label="Text style">
  <button type="button" class="button button--icon" aria-pressed="true">
    <svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Bold"/></svg>
    <span class="sr-only">Bold</span>
  </button>
  <button type="button" class="button button--icon" aria-pressed="false">
    <svg class="icon" width="1em" height="1em" aria-hidden="true" focusable="false"><use href="#Italic"/></svg>
    <span class="sr-only">Italic</span>
  </button>
</div>

Aligned with a utility

In a flex container (here a Card footer) the group is only as wide as its Buttons, so the container aligns it. On its own line, the utility goes on the group.

You have unsaved changes.

Code
HTML
<article class="card">
  <div class="card__body"><p class="text">You have unsaved changes.</p></div>
  <footer class="card__footer justify-end">
    <div class="button-group">
      <button type="button" class="button button--subtle"><span>Discard</span></button>
      <button type="button" class="button button--strong button--accent"><span>Save</span></button>
    </div>
  </footer>
</article>

<div class="button-group justify-center">
  <button type="button" class="button"><span>Previous</span></button>
  <button type="button" class="button"><span>Next</span></button>
</div>

Do and Don’t

DoDon’t
Align the group with a justify-* utility or the layout around it.Look for an alignment modifier on the group.
Use role="group" and a label for Buttons that share a purpose.Use role="toolbar", which promises arrow keys.
Put radio inputs inside the Buttons for an exclusive choice.Script the selection yourself.
Set looks for the group with .buttons-subtle and its siblings.Add a size or look to the group’s own modifiers.
Write text in a group as a text atom (.small-text).Look for a text part of the group.

In Storybook

See also

  • Button: An action on the page, such as saving a Form, opening a Dialog or changing a setting.
  • Menu: A list of actions in rows, usually opened from a Button in a Popover.
  • Divider: A rule between groups of content.
  • Batch Actions: The bar shown while items are selected, with how many, the actions on them and a way to clear the selection.

Search the docs