Skip to main content

Design system components

Radio

Single radio option; compose with RadioGroup for sets.

Status: beta. Group: form. Markdown version: /design-system/components/radio.md

When to use

Radio is one labelled option of an exclusive set. It is a low-level atom: in almost every case reach for RadioGroup, which owns the fieldset legend, the shared name, and the selection state. Use Radio directly only when composing a custom exclusive control.

When not to use

The contract records no forbidden uses.

Look-alikes

  • Checkbox: Do not render a lone radio; a choice with one option is a Checkbox.

Props

Radio props
PropTypeDefaultDescriptionRequired
labelstringnoneOption label.Yes
valuestringnoneSubmitted value when selected.Yes
namestringnoneGroup name; must match siblings to form the exclusive set.Yes
checkedbooleannoneChecked state (controlled); use inside RadioGroup for sets.No
defaultCheckedbooleannoneInitial checked state (uncontrolled mode only)No
disabledbooleanfalseDisables interaction and dims the control.No
size"sm" | "md" | "lg" | "S" | "M" | "L"mdControl hit area.No
onCheckedChange(checked: boolean) => voidnoneFired with the next checked value when selection changes.No
showLabelbooleantrueRender the visible label.No

Variants

  • Available sizes: sm, md, lg, S, M, L (default sm).

Invalid combinations

  • MUST NOT: checked and defaultChecked set together. checked makes the component controlled and defaultChecked uncontrolled; pass one, not both.

Keyboard

The contract records no keyboard interaction.

Rules

Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.

Radio rules
LevelRuleHow it is checked
MUST NOTchecked and defaultChecked set together. checked makes the component controlled and defaultChecked uncontrolled; pass one, not both.Checked by the MCP tool validate_component_usage.
MUSTRequired stories produce no axe violations at the configured severity.Automated by npm run test:stories:matrix:ci. WCAG 2.5.8.
MUSTThe accessibility tree (role, name, state) matches the committed snapshot for every required story.Automated by npm run test:stories:matrix:ci. WCAG 1.3.1, 4.1.2.
MUSTThe component remains legible and operable under a real browser forced-colors: active pass.Automated by npm run test:stories:hc.
MUSTA human completed an end-to-end accessibility review of this component.Manual review, last on 2026-05-28.
SHOULDGive every radio in a set the same name so the browser enforces exclusivity.Not stated in the contract.
SHOULDPrefer RadioGroup for sets; it wires the legend, selection state, and error text.Not stated in the contract.
SHOULDUse defaultChecked for uncontrolled forms that read values on submit.Not stated in the contract.
SHOULDKeep labels short and parallel; the group's legend carries the question.Not stated in the contract.
SHOULD NOTDo not render a lone radio; a choice with one option is a Checkbox.Not stated in the contract.
SHOULD NOTDo not set checked without onCheckedChange; a controlled radio that cannot change traps keyboard users.Not stated in the contract.
MUST NOTMaintainers: Do not bypass design tokens or skip forced-colors verification at beta.Release review; not machine-checked.

Install and import

  • Install: npm install @digitaltableteur/react (version 0.9.1, restricted access on npm).
  • Import: import { Radio } from "@digitaltableteur/react";
  • Entry point: @digitaltableteur/react/forms exports it too.
  • Styles: import @digitaltableteur/react/style.css once at the app boundary.
  • Also available as the custom element <dt-radio>; see the custom elements manifest.