# Radio

## Overview

The radio component is a single-select form control for choosing exactly one option from a related set.

The component pattern uses a native `<fieldset>` with a native `<legend>` and native radio inputs inside wrapping `<label>` elements, so the group keeps its semantics without requiring classed wrappers.

## When to use

Use radios when users must choose one option from a small set that should remain visible.

## When not to use

Do not use radios for a long list or choices that should remain collapsed until interaction; use select.

Use a radio button group only for a small set of short, mutually exclusive form choices. Use standard radios when labels are long or options need descriptions, and a select when the list is large or should stay collapsed. Use checkboxes when multiple choices are allowed. Use links for navigation, tabs for switching between content panels, and action buttons for commands; a radio selection represents a form value.

For button-style groups, omit a visible legend when the option labels make the choice clear. Add a legend when more context is needed. When no legend is shown, provide an accessible group name with `aria-label`.

## Usage

Use `fieldset[role="group"]` for joined button-style radio choices. Native inputs remain accessible and submit a form value. Use grouped buttons for related actions. Add `.chips` to retain chip styling in a wrapping row.


```html
<fieldset>
  <legend>Contact method</legend>
  <label>
    <input type="radio" name="contact-method" value="email" checked />
    Email
  </label>
  <label>
    <input type="radio" name="contact-method" value="phone" />
    Phone
  </label>
</fieldset>
```

Use this component when the user must pick one option from a small, always-visible set.

Use a select instead when the list is longer or should stay collapsed until interaction.

The group should use native `<fieldset>` and `<legend>` elements so assistive technology announces the shared question and the currently selected option in context.

Each radio should stay inside its own wrapping `<label>` so the full text remains clickable without extra helper markup.

## Behavior

Covered by [Playwright behavior tests](../../tests/e2e/forms-inputs.spec.js).

- RDO-001: The group stacks options with shared layout theme spacing rather than radio-specific density values.
- RDO-002: By default, each option keeps native radio rendering and browser interaction while the accent color follows the shared primary token.
- RDO-003: Disabled options should dim through shared text tokens rather than bespoke disabled colors.
- RDO-004: Focus must remain clearly visible for keyboard users.
- RDO-005: `fieldset[role="group"]` presents native radio choices as joined buttons while preserving keyboard selection and submitted values. Groups size to their contents by default; add `.fluid` to fill the available width.

## Accessibility

- Use a native `<fieldset>` and `<legend>` for related radio questions instead of a plain container and heading.
- Give every radio in the group the same `name` so browsers enforce the single-selection rule.
- Wrap each radio in a native `<label>` so the label text enlarges the interactive target.
- Keep option text descriptive enough to make sense when announced on its own.
- Do not replace the native radio with custom scripted markup unless the product truly requires behavior the platform cannot provide.

## Variables

| Variable | Type | Description |
| --- | --- | --- |
| `--radio-color-primary` | `<color>` | Sets --radio-color-primary so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-color-primary-subtle` | `<color>` | Sets --radio-color-primary-subtle so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-color-text` | `<color>` | Sets --radio-color-text so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-color-text-accent` | `<color>` | Sets --radio-color-text-accent so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-color-text-subtle` | `<color>` | Sets --radio-color-text-subtle so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-control-border-width` | `<length>` | Sets --radio-control-border-width so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-control-gap` | `<length>` | Sets --radio-control-gap so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-focus-ring-size` | `<length>` | Sets --radio-focus-ring-size so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-font-family-sans` | `Any` | Sets --radio-font-family-sans so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-font-size` | `<length>` | Sets --radio-font-size so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-line-height` | `<number>` | Sets --radio-line-height so the component can default to shared theme or layout tokens while exposing an overrideable component API. |
| `--radio-space-inline` | `<length>` | Sets --radio-space-inline so the component can default to shared theme or layout tokens while exposing an overrideable component API. |

## Depends On

- `--color-primary`
- `--color-primary-subtle`
- `--color-text`
- `--color-text-accent`
- `--color-text-subtle`
- `--font-family-sans`
- `--font-line-height-body`
- `--font-size`
- `--layout-control-border-width`
- `--layout-control-gap`
- `--layout-control-min-height`
- `--layout-control-padding-block`
- `--layout-control-padding-inline`
- `--layout-control-radius`
- `--layout-focus-ring-size`
- `--layout-space-inline`
