Radio Button

Atom

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

✅ Do
  • 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 name attribute so the browser enforces single-select
  • Always pre-select the most common or safest default option
❌ Don't
  • 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.

  1. 1Hidden input.radio-input. Visually hidden but focusable. Drives all states via CSS :checked, :disabled, :focus-visible using the ~ sibling selector.
  2. 2Circle.radio-box. The visible outer ring. Background and border change per state.
  3. 3Dot.radio-dot. The inner filled circle. Hidden by default; shows when :checked via CSS.
  4. 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.

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

Default
Hover
Disabled
Unselected
Selected

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 / BehaviourValueNotes
RoleradioImplicit from native <input type="radio">
Keyboard — selectSpaceSelects the focused radio button
Keyboard — move within group Arrow keys move focus AND selection within a radio group
Keyboard — between groupsTab / Shift+TabMoves focus between groups and other interactive elements
Groupingname="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
disabledHTML booleanRemoves the radio from tab order and blocks interaction

API

Class / attrOnDescription
.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.radioDocumentation helper — forces the hover visual at rest. Used in the Full matrix; not needed in production.