Skip to content

Accessibility

The Tab Picker is a radio group, not a tablist — it follows the WAI-ARIA Radio Group pattern and meets WCAG 2.1 AA. It borrows the tab strip’s visual from Tabs, but nothing about its accessibility comes from that resemblance: an accessible picker announces itself as a named group of mutually exclusive options, exposes exactly one of them as checked, and stays fully operable from the keyboard — so the current choice is clear whether the user is looking at it, listening to it, or tabbing through it.

  • All states (rested, hover, active, focus, and disabled) must maintain accessible contrast on every supported surface. Source: WCAG 1.4.3 Contrast (Minimum).
  • Selection must never rely on colour alone — reinforce it with the emphasised label weight and the active border, so it survives for colour-blind users. Source: WCAG 1.4.1 Use of Color.
  • Focus styles must stay visible, meet contrast requirements on every supported surface, and be clearly distinguishable from hover and from the selected state. Source: WCAG 2.4.7 Focus Visible.
  • Disabled options must stay readable while clearly reading as unavailable.
  • Use semantic colour tokens (e.g. foreground/neutral/default) rather than fixed values, so the component adapts correctly across themes and surfaces.

Build the picker from a native <fieldset> of <input type="radio"> elements sharing one name. It needs no ARIA and no JS: single-select, roving focus, and the group itself all come from the browser. Do not add role="tablist", role="tab", or role="radiogroup" — the native fieldset and radios already expose the group, and a tablist role would promise content panels the picker doesn’t have. Each radio is visually hidden but stays focusable and present in the accessibility tree, so it announces as “radio button, n of m, group name”.

The per-element roles, names, and states are in the Labelling elements section below.

The picker is fully operable from the keyboard, and every key below is native radio-group behaviour rather than something the consumer wires up. Source: WCAG 2.1.1 Keyboard.

Key Action
Tab Move focus into the group (the checked option), then out again
Shift + Tab Move focus to the previous interactive element
/ Move to and select the previous option
/ Move to and select the next option
Space Select the focused option

Because the arrow keys select as they move, a picker should never be wired so that changing the selection navigates or submits — that would strand keyboard users mid-row.

Interactive targets must be large enough for comfortable touch use, comfortably clearing the WCAG AA minimum. Source: WCAG 2.5.8 Target Size (Minimum).

The whole group is a single stop in the page’s tab sequence: Tab lands on the checked option (or the first option when none is checked), and a further Tab leaves the group entirely — the arrow keys rove between options from there. The keys that drive this are in the Keyboard interaction table above.

Battery
  1. Focused option

Source: WCAG 2.4.3 Focus Order.

Give every element the role, name, and state assistive technology needs.

Group

The native <fieldset> exposes the radio group — no role is needed or wanted. Its <legend> is the group’s accessible name, and it is required even though the design shows no visible label: hide it with sr-only rather than dropping it, or the options announce with no indication of what they belong to.

Option

Each <input type="radio"> takes its accessible name from the <label> text wrapping it, so no aria-label is needed — keep labels short and self-describing. All options in one picker must share a single name attribute; that attribute is what makes them mutually exclusive.

Selected state

The checked radio is the selection, exposed through native :checked rather than aria-selected or aria-current. Ship exactly one option checked in the initial markup so the group never announces as having no value.

Disabled option

Disable the nested <input> with the native disabled attribute, not the <label> and not an .is-disabled class. The browser then removes the option from the group’s arrow-key roving and announces it as unavailable.

Source: WCAG 4.1.2 Name, Role, Value.