Button groups

Button groups

Related buttons that bump and reshape against each other, in two variants and five sizes.

A button group places related buttons in one visual cluster. Use it for commands such as playback controls or for toggle buttons such as text formatting. Each item remains a native button and a Tab stop.

The root is a <div class="button-group">. Common buttons and icon buttons can be direct children. Expressive.AutoInit() keeps standard-group width stable while the pressed item grows; data-selection additionally enables managed toggle state.

<div class="button-group" data-selection="multiple"
     role="group" aria-label="Text formatting">
  <button type="button" class="button tonal" aria-pressed="false">
    <span class="material-symbols" aria-hidden="true">format_bold</span>
    Bold
  </button>
  <button type="button" class="button tonal" aria-pressed="false">
    <span class="material-symbols" aria-hidden="true">format_italic</span>
    Italic
  </button>
  <button type="button" class="button tonal" aria-pressed="false">
    <span class="material-symbols" aria-hidden="true">format_underlined</span>
    Underline
  </button>
</div>

Use a plain group for commands. Add selection behavior only when pressing a button toggles an on/off state. Use a segmented button when two to five choices form a compact form field whose value belongs in radios or checkboxes.

Standard

Standard is the default. Items keep separate shapes, and the gap closes as the size grows: 18dp at xsmall, 12dp at small, and 8dp from medium through xlarge. Pressing an item widens it by 15% of its measured width and morphs its corners toward the square shape for that size. The immediate neighbors provide the width, so the group's outer width stays fixed.

<div class="button-group" role="group" aria-label="Playback">
  <button type="button" class="icon-button filled" aria-label="Previous track">
    <span class="material-symbols" aria-hidden="true">skip_previous</span>
  </button>
  <button type="button" class="icon-button filled" aria-label="Play">
    <span class="material-symbols" aria-hidden="true">play_arrow</span>
  </button>
  <button type="button" class="icon-button filled" aria-label="Next track">
    <span class="material-symbols" aria-hidden="true">skip_next</span>
  </button>
</div>

Connected

Add connected to a selection group; do not use the connected treatment for one-shot actions. The group fills its container with equal items separated by 2dp. The outer ends remain round while the joins are squared off. The live M3 measurement keeps the xsmall join at 4dp; pressing small and medium changes their inner corners from 8dp to 4dp. The larger pairs are 16dp to 12dp at large and 20dp to 16dp at xlarge.

<div class="button-group connected"
     data-selection="single"
     data-selection-required
     role="group"
     aria-label="Text alignment">
  <button type="button" class="icon-button tonal"
          aria-label="Align left" aria-pressed="true">
    <span class="material-symbols" aria-hidden="true">format_align_left</span>
  </button>
  <button type="button" class="icon-button tonal"
          aria-label="Align center" aria-pressed="false">
    <span class="material-symbols" aria-hidden="true">format_align_center</span>
  </button>
  <button type="button" class="icon-button tonal"
          aria-label="Align right" aria-pressed="false">
    <span class="material-symbols" aria-hidden="true">format_align_right</span>
  </button>
</div>

Selection

A selection group contains toggle buttons. Add data-selection="single" when at most one item may be on, or data-selection="multiple" for independent toggles. Add data-selection-required when at least one must remain on. Give every item its initial aria-pressed value; ButtonGroup maintains it after AutoInit().

<div class="button-group connected"
     data-selection="multiple"
     role="group"
     aria-label="Text formatting">
  <button type="button" class="button filled" aria-pressed="true">Bold</button>
  <button type="button" class="button filled" aria-pressed="false">Italic</button>
  <button type="button" class="button filled" aria-pressed="false">Underline</button>
</div>

<script>
  Expressive.AutoInit();
</script>

Selection changes color, shape, and icon fill, so color is not the only cue. Native buttons provide Enter and Space activation; all items remain in the Tab order. Keep visible labels when space allows. Give an unfamiliar icon-only item a tooltip as well as an aria-label.

Sizes

Put xsmall, small (the default), medium, large, or xlarge on the group. Common and icon buttons inherit the matching 32dp, 40dp, 56dp, 96dp, or 136dp geometry. An explicit size on a child still wins. The 32dp and 40dp visual sizes keep a minimum 48dp interaction target.

<div class="button-group medium">
  <button type="button" class="button tonal">One</button>
  <button type="button" class="button tonal">Two</button>
  <button type="button" class="button tonal">Three</button>
</div>

Semantics

A button group is not a composite widget. Do not use role="toolbar", radiogroup, or a roving tabindex: items are reached with Tab. When the cluster needs a name, use role="group" with aria-label or aria-labelledby. This role adds no arrow-key contract.

Action groups accept a direct <button> or <a class="button" href>. Selection groups accept only direct <button type="button"> items, each with an initial aria-pressed. Links cannot expose toggle state. The native button supplies keyboard activation, and ButtonGroup changes the state on the resulting click.

Give every icon-only item an accessible name because its decorative icon is aria-hidden. Avoid a standard icon button when its meaning is not familiar; use a filled, tonal, or outlined container and a tooltip. Reduced-motion preferences remove the width and shape transitions.

Tokens

Set these properties on the group. The defaults describe a small standard group; size and variant classes replace the values that differ.

Token Default
--md-comp-button-group-between-space12px
--md-comp-button-group-pressed-item-width-multiplier.15
--md-comp-button-group-item-shape-round9999px
--md-comp-button-group-item-shape-square12px
--md-comp-button-group-pressed-item-shape8px
--md-comp-button-group-container-shape9999px (connected)
--md-comp-button-group-inner-corner-corner-size8px (connected)
--md-comp-button-group-pressed-inner-corner-corner-size4px (connected)
--md-comp-button-group-selected-inner-corner-corner-size50% (connected)

Child geometry and colors still come from the button or icon-button token family. Toggle groups map the selected and unselected Material button colors onto aria-pressed and retain hover, focus, pressed, disabled, and focus-ring feedback.

  • Source color

    The seed every generated ramp derives from. Pick one and browse the docs — the whole theme follows. Error does not: it is a fixed hue.