Radio
How the Radio works with a keyboard and assistive tech, and where it stands against WCAG 2.2 AA.
The Radio is a native <input type="radio"> under the drawn circle. Radios that share a name form one group, so the browser makes the group a single tab stop and moves the choice with the arrow keys. The component keeps that intact and names the group.
Keyboard#
Moves focus into the group, onto the chosen option, or the first one if none is chosen.
Moves focus out of the group, to the previous focusable element.
Moves to the next option and chooses it. → does the same. From the last option it wraps to the first.
Moves to the previous option and chooses it. ← does the same.
Chooses the focused option if it is not already chosen.
Semantics#
<input type="radio" name>Native role and keyboard. One shared name per group makes the arrow keys and the single tab stop work.
Alwaysrole="radiogroup"Or a <fieldset>. Give it a name with aria-label, aria-labelledby or a <legend>: Plan, Delivery speed.
A group<label>The row and card are label elements, so a click anywhere on them chooses the option.
Label row and cardaria-labelledbyPoints at the label text, so the option is named by its label alone.
Label row and cardaria-describedbyLinks the description, so it is read after the label.
descriptiondisabledThe option is skipped by Tab and by the arrow keys.
Disabled or Read OnlyColour contrast#
Every variant and state has to meet WCAG 2.2 Level AA. Measure the colours as they land on screen: a translucent hover or press wash over whatever sits behind it.
Chosen ring · Active
The 3px ring that marks the chosen option, against the page. Neutral #2a2a2a and Brand #005cf8 both clear it in every state.
WCAG 1.4.11 Non-text Contrast ↗Empty ring · Default
The 1.5px #e1e1e1 ring is the only thing that shows an option can be chosen. It measures 1.31:1 on white, under 3:1.
WCAG 1.4.11 Non-text Contrast ↗Label and description · Label row, Card
Label #2a2a2a and description #6d6d6d against white and a hovered card's 4% wash.
WCAG 1.4.3 Contrast (Minimum) ↗Chosen card · Card, Active
A chosen card changes its border, but the filled ring inside it is what carries the state. Keep the ring visible on every card.
WCAG 1.4.1 Use of Color ↗Focus indicator · Focus visible
A 2px ring in #1a6ef8 off a white gap, on keyboard focus only. It measures 4.54:1 on white, so it clears 3:1 on every light surface the library uses.
WCAG 1.4.11 Non-text Contrast ↗WCAG 2.4.13 Focus Appearance ↗Disabled · Disabled
Inactive controls are exempt. The disabled text and glyphs (#cbcbcb) are deliberately faint.
WCAG 1.4.3 Contrast (Minimum) ↗Measured contrast#
Each part against what sits directly behind it on a white page, from the ds.css tokens; text is held to 4.5:1 and the rings, as graphics, to 3:1. 3 of 15 pairs fall below their minimum (4.5:1 for text, 3:1 for graphics) and are marked in amber.
Motion#
- The ring and fill change over 120ms, and a card's wash over 150ms. Both are turned off under prefers-reduced-motion.
Checklist#
Every group has a name, and every option a visible label.
All radios in a group share one name; otherwise each becomes its own tab stop and the arrow keys stop working.
Choose a default only when one option is genuinely safe. With none chosen, Tab lands on the first option.
The circle is 16px but the input covers 24 × 24px, which meets WCAG 2.5.8.
The empty ring's #e1e1e1 is 1.31:1 on white, below 3:1. It needs a darker stroke before the code library ships.
Changing the choice should not move focus or submit anything. Act on it when the form is sent.
