# Radio Group

> Source: https://design.nanatec.co.ke/components/radio-group/
> Owns single selection across its `nana-radio` / `nana-radio-button` children. Implements the ARIA radiogroup keyboard pattern — arrow keys move and select, with roving tabindex — shares one `size`/`disabled`, and takes part in native forms through `name`/`value`.

Both child flavours are imported for you, so a group works with whichever the
markup uses.

## Preview

```html
<nana-radio-group label="Plan" name="plan" value="pro">
  <nana-radio value="free">Free</nana-radio>
  <nana-radio value="pro">Pro</nana-radio>
  <nana-radio value="team" disabled>Team</nana-radio>
</nana-radio-group>
```

## Installation

```bash
npm install @nana-tec/ui-components
```

## Import

```js
import "@nana-tec/ui-components/radio-group";
```

Already registered if you imported `@nana-tec/ui-components/radio`.

## Basic usage

```html
<nana-radio-group label="Plan" name="plan" value="pro">
  <nana-radio value="free">Free</nana-radio>
  <nana-radio value="pro">Pro</nana-radio>
</nana-radio-group>
```

React and Svelte ship the same group as `RadioGroup` — see
[Radio](/components/radio/) for both frameworks' props.

## Value

`value` is the single selected value, and it is what the group submits. The
group writes it back onto the children as `checked`, so it stays the one source
of truth no matter which child the user clicked or arrowed to.

```html
<nana-radio-group value="pro">
  <nana-radio value="free">Free</nana-radio>
  <nana-radio value="pro">Pro</nana-radio>
</nana-radio-group>
```

Only one `nana-change` fires per selection. The group swallows the child's own
event and re-emits its own with the same `detail.value`, so a listener on the
group never sees a duplicate.

## Shared state

`size` and `disabled` are set on the group and reach every child.

```html
<nana-radio-group label="Delivery" size="sm" disabled>
  <nana-radio value="standard">Standard</nana-radio>
  <nana-radio value="express" checked>Express</nana-radio>
</nana-radio-group>
```

A group-level `disabled` deliberately does **not** overwrite a child's own
`disabled`. It is applied at the group instead — the row container takes
`pointer-events: none` and the group carries `aria-disabled` — so an option
disabled on its own stays disabled when the group is re-enabled.

## Horizontal

`orientation="horizontal"` lays the options out in a row, which is what turns
`nana-radio-button` children into a segmented control.

```html
<nana-radio-group label="Billing period" orientation="horizontal" value="monthly">
  <nana-radio-button value="monthly">Monthly</nana-radio-button>
  <nana-radio-button value="yearly">Yearly</nana-radio-button>
  <nana-radio-button value="lifetime">Lifetime</nana-radio-button>
</nana-radio-group>
```

## Help text and errors

`help-text` sits beneath the options. Setting `error` replaces it with a
`role="alert"` message and flags every child invalid, which is what turns the
buttons red.

```html
<nana-radio-group label="Notifications" name="notify" value="" help-text="Choose how we reach you.">
  <nana-radio value="email" label="Email" description="Updates to your inbox"></nana-radio>
  <nana-radio value="sms" label="SMS" description="Texts to your phone"></nana-radio>
</nana-radio-group>

<nana-radio-group label="Seat count" name="seats" required error="Choose a billing period.">
  <nana-radio-button value="1">1 seat</nana-radio-button>
  <nana-radio-button value="5">5 seats</nana-radio-button>
</nana-radio-group>
```

Selecting an option clears `error`, so a message you set yourself disappears on
the next interaction.

## Forms

The group is a form-associated custom element: it submits `name=value`, and
`form.reset()` returns it to no selection. With `required` and nothing selected
it reports `valueMissing` against the message *"Please select an option."*, so
`:invalid` and `reportValidity()` work the way they do on a native control. A
browser restoring a back-navigated form sets the group back from its submitted
value.

```html
<form>
  <nana-radio-group label="Plan" name="plan" required>
    <nana-radio value="free">Free</nana-radio>
    <nana-radio value="pro">Pro</nana-radio>
  </nana-radio-group>
  <button type="submit">Continue</button>
</form>
```

## Keyboard

| Key | Does |
| --- | --- |
| `↓` `→` | Select the next option, wrapping |
| `↑` `←` | Select the previous option, wrapping |
| `Space` `Enter` | Select the focused option |

Arrow keys move *and* select, following the ARIA radiogroup pattern, and only
enabled options take part. Exactly one option is tabbable — the selected one, or
the first enabled option when nothing is selected — so `Tab` moves past the
group rather than through every radio in it.

## API

## Accessibility

- The host carries `role="radiogroup"` and each child `role="radio"` with a
  live `aria-checked`.
- The group is `aria-disabled` as a whole when `disabled`, and the legend shows
  a danger-coloured asterisk when `required`.
- Errors render in a `role="alert"`, so a message that appears after submit is
  announced.

## Related components

<ul class="related not-content">
  <li><a href="/components/radio/">Radio</a></li>
  <li><a href="/components/radio-button/">Radio Button</a></li>
  <li><a href="/components/checkbox/">Checkbox</a></li>
  <li><a href="/components/checkbox-group/">Checkbox Group</a></li>
  <li><a href="/components/switch/">Switch</a></li>
</ul>

## Storybook

See every state and prop interactively in Storybook: https://storybook.nanatec.co.ke/?path=/docs/components-radio-group--docs
