# RadioGroup

One choice out of a few options the user compares side by side. Each option is a 16px circle with its label after it and an optional description under the label; the picked one fills with the accent and shows an on-accent dot.

## Usage

### When to use

- Pick exactly one of two to five options the user should see and compare at once, such as a plan.
- Options that need a second line to say what they mean.

### When not to use

- More than five options, or options the user already knows, such as a country. Use Select.
- Turning one setting on or off. Use Switch.
- Picking several options. Use Checkbox.

## Variants

### orientation

Set on RadioGroup. vertical for options with descriptions or long labels; horizontal for two or three short ones. Arrow keys follow it.

Values: `vertical`, `horizontal`. Default: `vertical`.

## Examples

### Default

A visible heading names the group through aria-labelledby.

```tsx
<div className="flex flex-col gap-sm">
  <span id="plan-heading" className="text-sm font-medium text-text-primary">
    Plan
  </span>
  <RadioGroup aria-labelledby="plan-heading" defaultValue="pro">
    <RadioGroupItem value="free" label="Free" description="Up to 3 projects." />
    <RadioGroupItem value="pro" label="Pro" description="Unlimited projects and version history." />
    <RadioGroupItem value="team" label="Team" description="Pro, plus shared libraries and roles." />
  </RadioGroup>
</div>
```

### Short options in a row

```tsx
<RadioGroup aria-label="Theme" orientation="horizontal" defaultValue="system">
  <RadioGroupItem value="system" label="System" />
  <RadioGroupItem value="light" label="Light" />
  <RadioGroupItem value="dark" label="Dark" />
</RadioGroup>
```

### A disabled option

The arrow keys skip it.

```tsx
<RadioGroup aria-label="Region" defaultValue="eu">
  <RadioGroupItem value="eu" label="Europe" />
  <RadioGroupItem value="us" label="United States" />
  <RadioGroupItem value="ap" label="Asia Pacific" description="Coming later this year." disabled />
</RadioGroup>
```

## Do and don't

### Do

- Use it for two to five options the user should see and compare at once.
- Put a visible heading over the group and point aria-labelledby at it.
- Pick a default when one option is the usual choice.
- Add a description when the label alone doesn't say what the option means.

### Don't

- Don't use it for more than five options; use Select.
- Don't use it to turn one setting on or off; use Switch.
- Don't use it to pick several options; use Checkbox.

## Props

| Name | Type | Values | Default | Description |
| --- | --- | --- | --- | --- |
| `orientation` | `enum` | `vertical`, `horizontal` | `vertical` | Set on RadioGroup. vertical for options with descriptions or long labels; horizontal for two or three short ones. Arrow keys follow it. |
| `defaultValue` | `string` |  |  | Set on RadioGroup. The value picked on first render, when you don't control it. Pick a sensible default when one exists. |
| `value` | `string` |  |  | Set on RadioGroup. The picked value, when you control it. Pair it with onValueChange. |
| `onValueChange` | `function` |  |  | Set on RadioGroup. Called with the value of the newly picked option. |
| `disabled` | `boolean` |  | `false` | On RadioGroup, disables every option and dims the labels; on one RadioGroupItem, only that option. |
| `required` | `boolean` |  | `false` | Set on RadioGroup. An option must be picked to submit the form. |
| `name` | `string` |  |  | Set on RadioGroup. Form name; the form submits the picked value under it. |
| `label` | `node` |  |  | Set on RadioGroupItem. The visible name, after the circle. A press on it picks the option. |
| `description` | `node` |  |  | Set on RadioGroupItem. A second line under the label: what this option means. Needs label. |

### Slots

| Name | Required | Description |
| --- | --- | --- |
| `items` | yes | Two to five RadioGroupItem, each with a value and a label. |

## Anatomy

| Part | Description |
| --- | --- |
| `root` | RadioGroup: the options in a column (gap-md), or in a row that wraps (gap-x-lg, gap-y-md). |
| `item` | RadioGroupItem: a 16px circle, control border on the sunken fill. Picked, the accent fills it to the edge. |
| `indicator` | The dot in a picked circle: 6px, in the on-accent icon color (the indicator's ::after in currentColor). |
| `hitArea` | Transparent ::before centered on the circle, never smaller than size-target-min (24px on mouse, 44px on touch). |
| `row` | With label: the row that holds the circle, then the Label and the description, gap-sm. Shared with Checkbox and Switch. |
| `label` | With label: a Label after the circle, level with it on its first line. |
| `description` | With description: 13px secondary text under the label, gap-xs. |

## Accessibility

Role: `radiogroup`

| Keys | Action |
| --- | --- |
| `Tab` | Moves focus into the group, to the picked option (or the first one), and out of it. The group is one tab stop. |
| `Arrow keys` | Move to the next or previous option and pick it, wrapping from the last to the first. |
| `Space` | Picks the focused option when none is picked. |

- Name the group: aria-labelledby with the id of the visible heading over it, or aria-label. The type requires one of them.
- Name every option with the label prop; a press on the label picks it. description is linked with aria-describedby and read after the name.
- A disabled group dims every label; a disabled option is skipped by the arrow keys.
- Inside a form, a hidden input carries name and the picked value.
- The picked option differs from the others by its dot as well as its fill, so the choice never relies on color alone.

## Install

```bash
npx shadcn add https://werewolf-ui.vercel.app/r/radio-group.json
```

This also adds `styles/werewolf.css`, the tokens every component uses, and any other component it needs. Import that file once in your root CSS, after `@import "tailwindcss"`, with a path relative to that CSS file (from `app/globals.css` it is `@import "../styles/werewolf.css"`).
