CSS
A segmented control is a single-select group built entirely from native HTML — a <fieldset> wrapping same-name <input type="radio"> segments. Grouping, single-select, roving arrow-key navigation, and the accessible name all come from the platform: no ARIA roles and no JavaScript. State is keyed off the nested radio (:has(input:checked)), so it can never desync from the DOM.
Copy the block, give the radios a unique shared name, fill in the <legend>, and mark exactly one segment checked.
<fieldset class="tng-segmented-control"> <legend class="sr-only">Map view</legend> <label class="tng-segmented-control-item"> <input type="radio" name="view" value="list" checked /> <span>List</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="view" value="map" /> <span>Map</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="view" value="grid" /> <span>Grid</span> </label></fieldset>Elements
Section titled “Elements”Group label
Section titled “Group label”The <legend> is the group’s accessible name and is your responsibility to fill in. Keep it visually hidden with sr-only — the track is a flex row, so a visible <legend> would sit inside it as a segment and break the layout; convey the group’s purpose with nearby visible copy instead. Every segment in one control must share the same name, and exactly one must be checked.
One segment is a <label class="tng-segmented-control-item"> wrapping its own visually-hidden radio and a <span> carrying the label text. Each segment sizes to its own content, so a control with labels of different lengths has segments of different widths — that is intended, not a bug to correct.
Put .tng-overflow-ellipsis on the label <span>. A segment label is always one line: the utility pins white-space: nowrap so a longer label widens its segment instead of breaking onto a second line.
<fieldset class="tng-segmented-control"> <legend class="sr-only">Powertrain</legend> <label class="tng-segmented-control-item"> <input type="radio" name="powertrain" value="petrol" checked /> <span class="tng-overflow-ellipsis">Petrol</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="powertrain" value="hybrid" /> <span class="tng-overflow-ellipsis">Hybrid petrol</span> </label></fieldset>The control grows to fit its segments rather than shrinking them, so an over-long label widens the whole control instead of truncating. Keep labels to one or two words — if they don’t fit the space you have, a segmented control is the wrong component.
Variants
Section titled “Variants”Leading icon
Section titled “Leading icon”A segment can pair a leading .tng-icon with its label. Mark the icon aria-hidden="true" — the label text is the accessible name.
<fieldset class="tng-segmented-control"> <legend class="sr-only">Map view</legend> <label class="tng-segmented-control-item"> <input type="radio" name="view" checked /> <span class="tng-icon icon-list-ul" aria-hidden="true"></span> <span>List</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="view" /> <span class="tng-icon icon-map" aria-hidden="true"></span> <span>Map</span> </label></fieldset>Icon-only
Section titled “Icon-only”Add is-icon for compact square segments with no visible label. The icon is decorative (aria-hidden="true"); give each segment its accessible name with a visually-hidden sr-only span.
<fieldset class="tng-segmented-control is-icon"> <legend class="sr-only">Schedule view</legend> <label class="tng-segmented-control-item"> <input type="radio" name="schedule" checked /> <span class="tng-icon icon-list-ul" aria-hidden="true"></span> <span class="sr-only">List</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="schedule" /> <span class="tng-icon icon-calendar" aria-hidden="true"></span> <span class="sr-only">Calendar</span> </label></fieldset>Three text sizes set the segment typography and padding: is-sm, is-md (default), and is-lg.
<fieldset class="tng-segmented-control is-sm"> <legend class="sr-only">Range</legend> <label class="tng-segmented-control-item"> <input type="radio" name="range-sm" checked /> <span>Day</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="range-sm" /> <span>Week</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="range-sm" /> <span>Month</span> </label></fieldset><fieldset class="tng-segmented-control is-md"> <legend class="sr-only">Range</legend> <label class="tng-segmented-control-item"> <input type="radio" name="range-md" checked /> <span>Day</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="range-md" /> <span>Week</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="range-md" /> <span>Month</span> </label></fieldset><fieldset class="tng-segmented-control is-lg"> <legend class="sr-only">Range</legend> <label class="tng-segmented-control-item"> <input type="radio" name="range-lg" checked /> <span>Day</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="range-lg" /> <span>Week</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="range-lg" /> <span>Month</span> </label></fieldset>States
Section titled “States”Disabled
Section titled “Disabled”Disable a single segment with disabled on its radio, or the whole control with disabled on the <fieldset>. The native disabled attribute removes the affected segments from the tab order and conveys the state to assistive technologies automatically.
<fieldset class="tng-segmented-control"> <legend class="sr-only">View</legend> <label class="tng-segmented-control-item"> <input type="radio" name="view-1" checked /> <span>List</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="view-1" /> <span>Map</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="view-1" disabled /> <span>Grid</span> </label></fieldset><fieldset class="tng-segmented-control" disabled> <legend class="sr-only">View</legend> <label class="tng-segmented-control-item"> <input type="radio" name="view-2" checked /> <span>List</span> </label> <label class="tng-segmented-control-item"> <input type="radio" name="view-2" /> <span>Map</span> </label></fieldset>