Skip to content

Develop

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>
Map view

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.

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>
Map view

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>
Schedule view

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>
Range
Range
Range

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>
View
View