# StyledRadioGroup

> Slug: `styled-radio` · Category: Form Controls

## When to use

- Single-select where each option needs rich visual content: leading icon/image, body description, secondary label (price), status badge ("Best value"), or a trailing action.
- Plan pickers, payment methods, saved addresses, shipping options.

## When NOT to use

- Plain text-only options — use `RadioGroup`.
- Multi-select — use `Chips variant="toggle"` or a checkbox list.
- Single-line tag selection — use `Chips variant="radio"`.

## Variants & decision tree

Same data-driven shape as `RadioGroup` — pass `radioButtons`, NOT compound children. Each option supports decoration on multiple sides:

| Slot | Prop |
|---|---|
| Left icon/image | `leadingDecoration` + `leadingDecorationA11yLabel` |
| Bottom description | `body` |
| Right primary text | `secondaryLabel` |
| Right secondary text | `secondaryBody` |
| Status badge | `status` (string or `{ label, type, icon? }`) |
| Trailing action | `action` + `actionVariant: 'button' \| 'icon-button'` |

## States

Per option: unchecked, checked, focused, hover, disabled. Group: error (`errorMessage`), required (`ariaRequired`).

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `legend` | `string` | — | Required. Fieldset legend. |
| `groupName` | `string` | — | Required. Shared `name`. |
| `radioButtons` | `StyledRadioOption[]` | — | Required. Rich option array. |
| `value` / `defaultValue` | `string` | — | Controlled / uncontrolled. |
| `onChange` | `(value, event) => void` | — | Fires with selected value. |
| `errorMessage` | `string` | — | Group-level error. |
| `ariaInvalid` | `boolean` | `false` | Mark group invalid. |
| `ariaRequired` | `boolean` | `false` | Mark group required. |
| `legendAsLabel` | `boolean` | `false` | Visible legend treatment. |
| `inverse` | `boolean` | `false` | Dark-background styling. |

`StyledRadioOption`: `{ id, value, label, disabled?, leadingDecoration?, leadingDecorationA11yLabel?, body?, status?, secondaryLabel?, secondaryBody?, action?, actionVariant? }`.

`StyledRadioStatus`: `{ label, icon?, a11yLabel?, type?: 'positive' | 'caution' | 'critical' | 'info' | 'strong' }`.

## Usage examples

```tsx
<StyledRadioGroup
  legend="Available plans"
  groupName="plans"
  value={plan}
  onChange={(value) => setPlan(value)}
  radioButtons={[
    {
      id: 'basic',
      value: 'basic',
      label: 'Basic',
      body: 'Up to 300 Mbps',
      secondaryLabel: '$49/mo',
      status: { label: 'Best value', type: 'positive' },
    },
    {
      id: 'pro',
      value: 'pro',
      label: 'Gigabit Pro',
      body: 'Up to 1000 Mbps',
      secondaryLabel: '$99/mo',
    },
  ]}
/>
```

## Composition

Drop into a form to replace plain `RadioGroup` when options need price/decoration. Combine `action: <IconButton ... />` + `actionVariant="icon-button"` for editable rows (e.g., "Edit address").

## Accessibility

Renders a `<fieldset>` with a `<legend>`. `leadingDecorationA11yLabel` is required when the leading slot is purely visual (icon/image). `status` of type `'critical'` should also include `a11yLabel` so the badge is announced. `errorMessage` is wired via `aria-describedby`.

## Do / Don't

- DO use this when options carry price, status, or imagery.
- DO pair `actionVariant: 'icon-button'` with a real `IconButton` and an accessible `ariaLabel`.
- DON'T put interactive content inside `body` — use the `action` slot.
- DON'T mix this with `RadioGroup` in the same group — pick one shape.
