Radio

How the Radio works with a keyboard and assistive tech, and where it stands against WCAG 2.2 AA.

FreeReact and Vue
AAWCAG 2.2 target
12/15contrast pairs passing
5keyboard interactions

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#

Tab

Moves focus into the group, onto the chosen option, or the first one if none is chosen.

Shift+Tab

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.

Space

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.

Always
role="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 card
aria-labelledby

Points at the label text, so the option is named by its label alone.

Label row and card
aria-describedby

Links the description, so it is read after the label.

description
disabled

The option is skipped by Tab and by the arrow keys.

Disabled or Read Only

Colour 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.

3:1

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 ↗
3:1

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 ↗
4.5:1

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) ↗
Not colour alone

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 ↗
3:1

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 ↗
Not required

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.

Appearance · partRestHoverFocused
Neutral · chosen ring14.35passes20.14passes14.35passes
Brand · chosen ring5.40passes8.53passes5.40passes
Unchosen · ring1.31below the minimum1.27below the minimum1.31below the minimum
Card · label14.35passes13.17passes14.35passes
Card · description5.17passes4.75passes5.17passes

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.