Button Group

Molecule

A row (or column) of related buttons that should be visually grouped — toolbars, segmented controls, filter pills. Composes existing Button sizes and states. Use Secondary, Tertiary, or Ghost as the base variant; let the selected button carry the emphasis (primary fill via aria-pressed, or solid border via .btn-group-active-border).

When to use

✅ Do
  • Use when 2–5 related actions share the same context (Bold / Italic / Underline, filter pills)
  • Use Tertiary as the base variant for all buttons in a group — it reads as neutral and equal weight
  • Use Primary only for the active / selected button within the group
  • Use Attached variant when actions form a single logical control (segmented selector)
  • Use Separated variant when actions are related but independently triggerable
  • Keep all buttons in a group the same size
❌ Don't
  • Use Secondary or Ghost inside a group — Tertiary is the correct neutral base
  • Use more than one Primary button in the same group — only one button should be active at a time
  • Use for page-level navigation — use Tabs or sidebar Links instead
  • Mix variants inside a group (e.g. Primary next to Tertiary for non-active buttons)
  • Use more than 5 buttons in a single group — use a Dropdown instead

DigiLawyer Patterns

Button Group composes entirely with Button — all Button DigiLawyer Patterns carry over. The most relevant one for groups is shown below.

Inherits: Icon-only = single icon per button
Each button in an icon-only group must use exactly one icon with .btn-square. Never two icons inside a single button within the group.

Anatomy

A Button Group wraps two or more Button atoms. The wrapper controls spacing and border-radius; individual buttons remain structurally unchanged.

  1. 1Group wrapper.btn-group. Sets display: inline-flex and manages the gap or border-overlap between children.
  2. 2Left button.btn-pos-left. Rounds left corners only.
  3. 3Middle button(s).btn-pos-middle. No border-radius on any corner.
  4. 4Right button.btn-pos-right. Rounds right corners only.
  5. 5Active indicator — Optional. .btn-group-active-border on the wrapper shows a coloured left border on the selected button.

Default

Wrap related buttons in a .btn-group. Adjacent buttons share borders so the row reads as a single component. Use this for segmented controls.

HTML
<div class="btn-group">
  <button class="btn btn-tertiary btn-md"><span class="btn-label">Day</span></button>
  <button class="btn btn-tertiary btn-md"><span class="btn-label">Week</span></button>
  <button class="btn btn-tertiary btn-md"><span class="btn-label">Month</span></button>
  <button class="btn btn-tertiary btn-md"><span class="btn-label">Year</span></button>
</div>

Attached vs separated

.btn-group is attached by default (shared borders). Add .btn-group-separated for a gap-spaced group where each button keeps its own radius — use this when buttons are unrelated peers (action bars, multi-action toolbars).

Attached — segmented control
Separated — filter pills
HTML
<!-- Attached -->
<div class="btn-group">...</div>

<!-- Separated -->
<div class="btn-group btn-group-separated">...</div>

Sizes

Use a single size class on every button in the group. Mixing sizes inside a group is not supported.

Large
Medium
Small
X-Small

With icons

Icon-only and icon+label work inside groups. Icon-only buttons are common for toolbars (alignment, formatting). The standard <span class="icon"> wrapper auto-sizes per button size.

Icon only
Icon + label
Separated

Toggle / selection

For segmented controls where exactly one button is selected at a time, set aria-pressed="true" on the selected button (or class="active" if you don't need the semantics). Click any button below — only one stays selected.

HTML
<div class="btn-group" role="group" aria-label="View">
  <button class="btn btn-tertiary btn-md" aria-pressed="false">...</button>
  <button class="btn btn-tertiary btn-md" aria-pressed="true">...</button>
  <button class="btn btn-tertiary btn-md" aria-pressed="false">...</button>
</div>

// Every .btn-group on the page toggles by default — add data-no-toggle to opt out.
document.querySelectorAll('.btn-group:not([data-no-toggle]) .btn').forEach(b => {
  b.addEventListener('click', () => {
    b.closest('.btn-group')
      .querySelectorAll('.btn')
      .forEach(x => x.setAttribute('aria-pressed', x === b ? 'true' : 'false'));
  });
});

Vertical

Add .btn-group-vertical for a stacked column — useful in narrow sidebars or mobile layouts. Combines with .btn-group-separated.

Attached, vertical
Separated, vertical

States

Each button keeps its own disabled state. Disable an entire group by disabling all of its buttons, or a single button to indicate one option is unavailable.

Full matrix

A button-group's structure is defined by position: which corners are rounded and which borders collapse into the neighbouring button. The five position variants below are the building blocks — horizontal groups use Left / Middle / Right, vertical groups use Up / Middle / Down. Inside a real .btn-group these are applied automatically via :first-child / :last-child. The standalone .btn-pos-* helpers below let you visualise or hand-compose the same shapes.

Position = Left
Position = Middle
Position = Right
Position = Up
Position = Down

Accessibility

Follows the WAI-ARIA Toolbar pattern for action groups, or the Radio Group pattern for selection groups.

Attribute / BehaviourValueNotes
Wrapper role — toolbarrole="toolbar"Use when buttons are independent actions (Bold, Italic, Copy)
Wrapper role — selectionrole="group"Use when buttons form a mutually exclusive selection (Day / Week / Month)
Selected statearia-pressed="true"Set on the active button for toggle/selection groups
Keyboard — focusTabEach button is individually focusable
Keyboard — activateEnter / SpaceActivates the focused button
Icon-only buttonsaria-label requiredEach icon-only button must have a descriptive aria-label

API

ClassOnDescription
.btn-groupwrapperAttached horizontal group — adjacent buttons share borders. Default.
.btn-group-separatedwrapperModifier — adds --btn-group-gap between buttons, restores per-button radius.
.btn-group-verticalwrapperModifier — stacks buttons vertically. Combines with .btn-group-separated.
.btn-group-active-borderwrapperModifier — selected button adopts the .btn-active-border solid-border look instead of the primary fill. Use on a Tertiary base.
data-no-togglewrapperOpt out of the default click-to-toggle behaviour. Every .btn-group toggles by default.
.btn-pos-left / -middle / -rightbuttonPosition helpers for horizontal groups — corner radius + collapse the border that meets the neighbour. Applied automatically inside .btn-group; use explicitly only for hand-composed layouts or documentation.
.btn-pos-up / -downbuttonPosition helpers for vertical groups — top/bottom corner radius + collapse the meeting border.
role="group"wrapperRecommended ARIA role. Pair with aria-label.
aria-pressedbuttonSelected state for toggle/segmented controls. Styling matches .active.
.activebuttonCSS-only selected state — use when you don't need the ARIA semantics.
disabledbuttonHTML attribute — disables one or more buttons in the group.