Radio Button
A single-selection control from a mutually exclusive set. Built on a native <input type="radio"> — browser handles the "one of N" semantics via the shared name="…" attribute, so no JS is needed for state.
When to use
- Use when exactly one option must be selected from a mutually exclusive set
- Use when there are 2–6 options and all should be visible at once
- Use when users benefit from seeing all choices side by side to compare
- Group all radios with the same
nameattribute so the browser enforces single-select - Always pre-select the most common or safest default option
- Use when multiple options can be selected — use Checkbox instead
- Use when there are more than 6 options — use a Dropdown instead
- Use for a setting that takes effect immediately — use Toggle Switch instead
- Leave all options unselected — radio groups should always have a default
- Use a single standalone radio — a single choice is not a radio group
DigiLawyer Patterns
No additional product-specific patterns for Radio Button. The same label-positioning rule from Checkbox applies — radio button always appears on the left, label text always to the right.
Anatomy
A Radio Button is composed of a hidden native input, a visible circle, an inner dot, and a label. The dot appears via CSS when :checked — no JS needed.
- 1Hidden input —
.radio-input. Visually hidden but focusable. Drives all states via CSS:checked,:disabled,:focus-visibleusing the~sibling selector. - 2Circle —
.radio-box. The visible outer ring. Background and border change per state. - 3Dot —
.radio-dot. The inner filled circle. Hidden by default; shows when:checkedvia CSS. - 4Label —
.radio-label. Always placed to the right of the circle. Required for accessibility.
Default
Wrap a native radio input + a styled circle in a <label class="radio">. The input is visually hidden but stays in the focus path; the .radio-box renders the visible circle and the inner .radio-dot shows when :checked. Group radios with a shared name attribute.
<label class="radio"> <input type="radio" class="radio-input" name="plan" value="free" checked> <span class="radio-box"><span class="radio-dot"></span></span> <span class="radio-label">Free</span> </label>
Variants
Two visual states. Unselected shows an empty circle; Selected fills the circle and reveals the inner dot. Selection is mutually exclusive within a shared name group — checking one automatically unchecks its siblings.
States
Three interaction states. Hover and focus are CSS-driven (real interaction required, or use the .is-hover doc helper to force the visual). Disabled uses the HTML disabled attribute on the input.
Full matrix
2 variants × 3 states, mirroring the Figma source. Default row is interactive; Hover row uses the .is-hover documentation helper to force the hover visual at rest; Disabled row uses the native disabled attribute.
Accessibility
Built on a native <input type="radio"> — all ARIA semantics are implicit. Group all radios with a shared name attribute so the browser enforces single-select natively.
| Attribute / Behaviour | Value | Notes |
|---|---|---|
| Role | radio | Implicit from native <input type="radio"> |
| Keyboard — select | Space | Selects the focused radio button |
| Keyboard — move within group | ↑ ↓ ← → | Arrow keys move focus AND selection within a radio group |
| Keyboard — between groups | Tab / Shift+Tab | Moves focus between groups and other interactive elements |
| Grouping | name="group-name" | All radios in a group must share the same name — this is what makes them mutually exclusive |
| Group label | <fieldset> + <legend> | Wrap groups in a fieldset with a legend to give screen readers a shared group name |
disabled | HTML boolean | Removes the radio from tab order and blocks interaction |
API
| Class / attr | On | Description |
|---|---|---|
| .radio | <label> | Wrapper. Makes the whole row a click/tap target for the input inside. |
| .radio-input | <input type="radio"> | The native input, visually hidden but accessible and focusable. Drives the visual via :checked / :disabled. |
| .radio-box | <span> | The visible 16×16 circle with border and fill. |
| .radio-dot | <span> | The inner 6×6 dot that appears when the input is :checked. |
| .radio-label | <span> | The text label. Inherits muted color + reduced opacity when the input is disabled. |
| name | <input> | HTML attribute — radios with the same name form a single-selection group. Required for mutual exclusivity. |
| checked | <input> | HTML attribute — radio starts selected. Only one per name group should carry this. |
| disabled | <input> | HTML attribute — disables interaction; styling swaps to --radio-bg-disabled / --radio-checked-bg-disabled. |
| .is-hover | .radio | Documentation helper — forces the hover visual at rest. Used in the Full matrix; not needed in production. |