Fylgja Button Group

A button group is a segmented control: a row of joined buttons where exactly one is selected. It is built from radio inputs styled as buttons inside an input group, so it keeps real single-select semantics and needs no JavaScript.

Preview

<div role="group" aria-label="Text alignment" class="input-group --merge" style="--rounded: var(--radius-4); --btn-stroke: color-mix(in oklab, var(--root-bg) 70%, var(--root-fg))">
	<label class="btn"><input type="radio" name="align" checked>Left</label>
	<label class="btn"><input type="radio" name="align">Center</label>
	<label class="btn"><input type="radio" name="align">Right</label>
</div>

Usage

  • Wrap the options in a <div class="input-group --merge"> with role="group" and an aria-label. The --merge modifier collapses the doubled borders between the buttons so they read as one unit, and rounds the outer ends.
  • Each option is a <label class="btn"> containing an <input type="radio"> that shares one name. The input group hides the radios automatically, so no sr-only is needed.
  • Mark the default option’s radio checked. Fylgja’s button active style targets the label that :has(input:checked), so the selection highlights itself.
  • Set --rounded on the group for the pill shape and --btn-stroke for the border color.

Accessibility

  • Radios give arrow-key navigation and single-select for free; the input group hides them from view but keeps them operable via their labels.
  • The aria-label on the group names the set of choices.

Related: Button, Icon Button, Tabs.

FAQ

Why radios instead of buttons?

Radios give real single-select semantics for free, arrow-key navigation between options, only one chosen, and it submits with a form. The visible buttons are labels wrapping a visually hidden radio.

How does the selected option get highlighted?

Fylgja's button active style applies to a label that :has(input:checked), so the checked radio's label shows the active background with no JavaScript.

Should I add focusgroup="toolbar" to a button group?

Not to this radio version, since radios already form one Tab stop and move with the arrow keys. When the group holds action buttons instead, such as Bold, Italic, and Underline, add focusgroup="toolbar" to the wrapper. The group then becomes a single Tab stop with the arrow keys moving between the buttons, and a plain div gets the toolbar role, so role="group" can go. Browsers without focusgroup keep every button as its own Tab stop, and the Multiselect docs link a polyfill.