import { Meta, Canvas, Controls } from '@storybook/addon-docs/blocks';
import * as RadioStories from './radio.stories';

<Meta of={RadioStories} name="Guideline" />

<style>{`
  .sbdocs-content h2 { margin-top: 5rem; }
  .sbdocs-content h3 { margin-top: 3rem; }
  .sbdocs-content .sb-story { margin-bottom: 0.5rem; }
  .sbdocs-content .sbdocs-preview { margin-bottom: 1.5rem; }
`}</style>

# Radio

Radio buttons let users pick exactly one option from a group.

For guidance on when to use Checkbox vs Toggle vs Radio vs Select, see [Guidelines/Selection Controls](?path=/docs/guidelines-selection-controls--stories).

## Usage

Radio buttons are always used in a group. A single radio button on its own is meaningless. Use `RadioGroup` to render a set of options: it owns the selected value, the shared `name`, and the group's accessible label. Pass the choices as an `options` array of `{ value, label, disabled?, disabledReason? }`.

<Canvas of={RadioStories.RadioGroupExample} layout="fullscreen" sourceState="none" />

Use Radio when:
- The user must choose exactly one option from a set of 2 to 4 choices
- All options have equal semantic weight and distinct labels
- The options need to be visible at once (unlike Select, which hides them behind a dropdown)

Use Select instead when the list of options is long or dynamic. Use Checkbox when multiple selections are valid.

## Layout

Radio buttons can be arranged vertically (default) or horizontally via the `direction` prop. There is no rule: use whichever fits the available space and the length of the labels. Vertical is generally easier to scan when labels are long.

<Canvas of={RadioStories.Horizontal} layout="fullscreen" sourceState="none" />

## Label conventions

Radio labels describe the option itself, not an action or a state. Keep them short and parallel in structure across the group.

- "Governance / Compliance / None" not "Enable governance / Enable compliance / Disable"
- "Small / Medium / Large" not "Set to small / Set to medium / Set to large"

## States

<Canvas of={RadioStories.AllStates} layout="fullscreen" sourceState="none" />

The four visual states from left to right: unchecked, checked, disabled, disabled checked.

**Unchecked** is the default state. You can pre-select the preferred or most common option by default. Place it at the top of the group. Alternatively, leave all options unchecked to force the user to make an explicit choice. Both are valid depending on context.

**Disabled checked** indicates the current selection is locked and cannot be changed. Use it when a value is enforced by configuration or permissions and the user should see what is set without being able to modify it.

**Disabled unchecked** means the option exists but is not available in the current context. When an explanation is needed, set `disabledReason` on the option — a tooltip will appear on hover.

<Canvas of={RadioStories.WithDisabledReason} layout="fullscreen" sourceState="none" />

When an entire group is disabled, pass `disabled` on `RadioGroup` rather than on each option — all options will be disabled together.

<Canvas of={RadioStories.DisabledGroup} layout="fullscreen" sourceState="none" />

## Accessibility

Radio buttons are natively accessible when used correctly. The browser handles keyboard interaction automatically.

### Keyboard behavior

| Key | Action |
| --- | --- |
| Tab | Moves focus into the group (lands on the selected option, or the first if none selected) |
| Arrow keys | Moves between options within the group and selects them |
| Shift+Tab | Moves focus out of the group |

Arrow-key navigation only works between radios that share the same `name`. This is why `name` is required on `RadioGroup`.

### Group label

A radio group needs an accessible name so screen readers can announce what the group is about. `RadioGroup` accepts the label from one of three sources — pick whichever fits the surrounding layout:

1. **`label` prop** — renders a `<fieldset>` with a `<legend>`. Use this for standalone groups.
2. **`aria-labelledby` prop** — points to an existing visible label rendered elsewhere. Use this when the label is provided by a wrapping component (e.g. `FormGroup`) so the label is not duplicated.
3. **`aria-label` prop** — invisible label. Use this when the surrounding context (e.g. a table row) already makes the meaning clear visually but a screen reader still needs a name.

Exactly one of these must be set. A `RadioGroup` with no accessible name is invisible to screen readers.

#### Inside a FormGroup

`FormGroup` already renders its own visible label and exposes it with the id `label-{id}`. Wire `RadioGroup` to that label via `aria-labelledby` — do not also pass `label` to `RadioGroup`, or the label would appear twice.

<Canvas of={RadioStories.FormGroupExample} layout="fullscreen" sourceState="none" />

#### Without a visible label

When the radio group is used without a visible label — for example inside a table row where the row itself provides context — pass `aria-label` directly.

<Canvas of={RadioStories.WithoutVisibleLabel} layout="fullscreen" sourceState="none" />
