# Radio Group

<FrameworkCodeSwitcher>
  <div slot="astro">
```astro
---
import { RadioGroup, RadioGroupItem } from "@/components/starwind/radio-group";
import { Label } from "@/components/starwind/label";
---

<RadioGroup name="demo-radio" defaultValue="option-1" legend="Choose an option">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="option-1" aria-label="Option 1" value="option-1" />
    <Label for="option-1">Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="option-2" aria-label="Option 2" value="option-2" />
    <Label for="option-2">Option 2</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="option-3" aria-label="Option 3" value="option-3" />
    <Label for="option-3">Option 3</Label>
  </div>
</RadioGroup>
```
  </div>
  <div slot="react">
```tsx
import { RadioGroup, RadioGroupItem } from "@/components/starwind/radio-group";
    import { Label } from "@/components/starwind/label";

export function Example() {
  return (
    <>
      <RadioGroup name="demo-radio" defaultValue="option-1" legend="Choose an option">
            <div className="flex gap-2 items-center">
              <RadioGroupItem id="option-1" aria-label="Option 1" value="option-1" />
              <Label htmlFor="option-1">Option 1</Label>
            </div>
            <div className="flex gap-2 items-center">
              <RadioGroupItem id="option-2" aria-label="Option 2" value="option-2" />
              <Label htmlFor="option-2">Option 2</Label>
            </div>
            <div className="flex gap-2 items-center">
              <RadioGroupItem id="option-3" aria-label="Option 3" value="option-3" />
              <Label htmlFor="option-3">Option 3</Label>
            </div>
          </RadioGroup>
    </>
  );
}
```
  </div>
</FrameworkCodeSwitcher>

> **Info:** Each `RadioGroupItem` has an explicit accessible name. The Runtime-backed styled item renders a
focusable `role="radio"` element separately from its hidden form input.

## Installation

```bash
npx starwind@latest add radio-group
```

## Usage

### variant

```astro
---
import { RadioGroup, RadioGroupItem } from "@/components/starwind/radio-group";
import { Label } from "@/components/starwind/label";
---

<RadioGroup name="variant-radio" legend="Default" defaultValue="default-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="default-1" aria-label="Default Option 1" value="default-1" variant="default" />
    <Label for="default-1">Default Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="default-2" aria-label="Default Option 2" value="default-2" variant="default" />
    <Label for="default-2">Default Option 2</Label>
  </div>
</RadioGroup>

<RadioGroup name="variant-primary" legend="Primary" defaultValue="primary-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="primary-1" aria-label="Primary Option 1" value="primary-1" variant="primary" />
    <Label for="primary-1">Primary Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="primary-2" aria-label="Primary Option 2" value="primary-2" variant="primary" />
    <Label for="primary-2">Primary Option 2</Label>
  </div>
</RadioGroup>

<RadioGroup name="variant-secondary" legend="Secondary" defaultValue="secondary-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="secondary-1" aria-label="Secondary Option 1" value="secondary-1" variant="secondary" />
    <Label for="secondary-1">Secondary Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="secondary-2" aria-label="Secondary Option 2" value="secondary-2" variant="secondary" />
    <Label for="secondary-2">Secondary Option 2</Label>
  </div>
</RadioGroup>

<RadioGroup name="variant-info" legend="Info" defaultValue="info-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="info-1" aria-label="Info Option 1" value="info-1" variant="info" />
    <Label for="info-1">Info Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="info-2" aria-label="Info Option 2" value="info-2" variant="info" />
    <Label for="info-2">Info Option 2</Label>
  </div>
</RadioGroup>

<RadioGroup name="variant-success" legend="Success" defaultValue="success-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="success-1" aria-label="Success Option 1" value="success-1" variant="success" />
    <Label for="success-1">Success Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="success-2" aria-label="Success Option 2" value="success-2" variant="success" />
    <Label for="success-2">Success Option 2</Label>
  </div>
</RadioGroup>

<RadioGroup name="variant-warning" legend="Warning" defaultValue="warning-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="warning-1" aria-label="Warning Option 1" value="warning-1" variant="warning" />
    <Label for="warning-1">Warning Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="warning-2" aria-label="Warning Option 2" value="warning-2" variant="warning" />
    <Label for="warning-2">Warning Option 2</Label>
  </div>
</RadioGroup>

<RadioGroup name="variant-error" legend="Error" defaultValue="error-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="error-1" aria-label="Error Option 1" value="error-1" variant="error" />
    <Label for="error-1">Error Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="error-2" aria-label="Error Option 2" value="error-2" variant="error" />
    <Label for="error-2">Error Option 2</Label>
  </div>
</RadioGroup>
```

> **Info:** Variant styling does not change the radio contract, so every item keeps an explicit accessible
name in addition to its visible label.

### size

```astro
---
import { RadioGroup, RadioGroupItem } from "@/components/starwind/radio-group";
import { Label } from "@/components/starwind/label";
---

<RadioGroup name="size-sm" legend="Small" defaultValue="sm-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="sm-1" aria-label="Small Option 1" value="sm-1" size="sm" />
    <Label for="sm-1" size="sm">Small Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="sm-2" aria-label="Small Option 2" value="sm-2" size="sm" />
    <Label for="sm-2" size="sm">Small Option 2</Label>
  </div>
</RadioGroup>

<RadioGroup name="size-md" legend="Medium" defaultValue="md-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="md-1" aria-label="Medium Option 1" value="md-1" size="md" />
    <Label for="md-1" size="md">Medium Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="md-2" aria-label="Medium Option 2" value="md-2" size="md" />
    <Label for="md-2" size="md">Medium Option 2</Label>
  </div>
</RadioGroup>

<RadioGroup name="size-lg" legend="Large" defaultValue="lg-1">
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="lg-1" aria-label="Large Option 1" value="lg-1" size="lg" />
    <Label for="lg-1" size="lg">Large Option 1</Label>
  </div>
  <div class="flex gap-2 items-center">
    <RadioGroupItem id="lg-2" aria-label="Large Option 2" value="lg-2" size="lg" />
    <Label for="lg-2" size="lg">Large Option 2</Label>
  </div>
</RadioGroup>
```

> **Info:** Size only changes presentation; each focusable Runtime radio remains explicitly named.

### orientation

```astro
---
import { RadioGroup, RadioGroupItem } from "@/components/starwind/radio-group";
import { Label } from "@/components/starwind/label";
---

<h3>Vertical (Default)</h3>
<RadioGroup name="orientation-vertical" orientation="vertical" defaultValue="vertical-1">
  <div class="space-y-2">
    <div class="flex items-center gap-2">
      <RadioGroupItem id="vertical-1" aria-label="Vertical option 1" value="vertical-1" />
      <Label for="vertical-1">Vertical option 1</Label>
    </div>
    <div class="flex items-center gap-2">
      <RadioGroupItem id="vertical-2" aria-label="Vertical option 2" value="vertical-2" />
      <Label for="vertical-2">Vertical option 2</Label>
    </div>
    <div class="flex items-center gap-2">
      <RadioGroupItem id="vertical-3" aria-label="Vertical option 3" value="vertical-3" />
      <Label for="vertical-3">Vertical option 3</Label>
    </div>
  </div>
</RadioGroup>

<h3>Horizontal</h3>
<RadioGroup name="orientation-horizontal" orientation="horizontal" defaultValue="horizontal-1">
  <div class="flex items-center gap-2">
    <RadioGroupItem id="horizontal-1" aria-label="Horizontal option 1" value="horizontal-1" />
    <Label for="horizontal-1">Horizontal option 1</Label>
  </div>
  <div class="flex items-center gap-2">
    <RadioGroupItem id="horizontal-2" aria-label="Horizontal option 2" value="horizontal-2" />
    <Label for="horizontal-2">Horizontal option 2</Label>
  </div>
  <div class="flex items-center gap-2">
    <RadioGroupItem id="horizontal-3" aria-label="Horizontal option 3" value="horizontal-3" />
    <Label for="horizontal-3">Horizontal option 3</Label>
  </div>
</RadioGroup>
```

> **Info:** Give each Runtime radio an explicit accessible name. The styled radio uses a focusable
`role="radio"` element while its hidden input handles native form participation.

### Event Handling

The RadioGroup component emits a `starwind:value-change` event when a radio option is selected. This can be listened to in order to update your UI based on the `event.detail.value` property.

```astro
---
import { RadioGroup, RadioGroupItem } from "@/components/starwind/radio-group";
import { Label } from "@/components/starwind/label";
---

<div class="space-y-4">
  <h3 class="text-lg font-medium">Radio Group Event Test</h3>

  <RadioGroup id="event-test" name="event-test" legend="Choose an option">
    <div class="flex gap-2">
      <RadioGroupItem id="event-1" aria-label="Option One" value="one" />
      <Label for="event-1">Option One</Label>
    </div>
    <div class="flex gap-2">
      <RadioGroupItem id="event-2" aria-label="Option Two" value="two" />
      <Label for="event-2">Option Two</Label>
    </div>
    <div class="flex gap-2">
      <RadioGroupItem id="event-3" aria-label="Option Three" value="three" />
      <Label for="event-3">Option Three</Label>
    </div>
  </RadioGroup>

  <div id="event-output" class="text-muted-foreground text-sm">
    Selected value: <span class="text-foreground font-medium">none</span>
  </div>
</div>

<script>
  const root = document.querySelector<HTMLElement>("#event-test");
  const output = document.querySelector<HTMLElement>("#event-output span");

  root?.addEventListener("starwind:value-change", (event) => {
    const { value } = (event as CustomEvent<{ value: string }>).detail;
    if (output) output.textContent = value;
  });
</script>
```

> **Info:** Listen on the Radio Group root. Runtime value-change details include `value`, `previousValue`,
`radioValue`, and `reason`; listeners no longer need a component-id detail field. Each item also
keeps an explicit accessible name on the focusable Runtime radio.

## Framework Availability
Radio Group is available for Astro and React.
Astro available; React available
| Framework | Status | Notes |
| --- | --- | --- |
| Astro | available | - |
| React | available | - |
## API Reference
### RadioGroup
| Prop | Type | Required | Default | Kind | Description |
| --- | --- | --- | --- | --- | --- |
| `defaultValue` | `string` | No | - | Primitive override | Sets the initial value when the component is uncontrolled. |
| `legend` | `string` | No | - | Wrapper prop | Provides accessible text for the grouped choices. |
| `orientation` | `"vertical" \| "horizontal"` | No | `"vertical"` | Styled variant | Selects the horizontal or vertical layout direction. |
| `value` | `string` | No | - | Primitive override | Controls or identifies the component value. |
- Inherits div attributes. Omits `defaultValue` and `onChange`.

### RadioGroupItem
| Prop | Type | Required | Default | Kind | Description |
| --- | --- | --- | --- | --- | --- |
| `defaultChecked` | `boolean` | No | - | Primitive override | Sets the initial checked state when the choice is uncontrolled. |
| `size` | `"sm" \| "md" \| "lg"` | No | `"md"` | Styled variant | Selects the component's visual size. |
| `variant` | `"default" \| "primary" \| "secondary" \| "info" \| "success" \| "warning" \| "error"` | No | `"primary"` | Styled variant | Selects the component's visual variant. |
- Inherits span attributes. Omits `defaultChecked` and `onChange`.
### Primitive And Runtime API
Behavior, state, events, form participation, and imperative methods are documented in the lower-level references.
- Primitive: [Radio Primitive](/docs/primitives/radio/)
- Primitive: [Radio Group Primitive](/docs/primitives/radio-group/)
- Runtime factory: [`createRadio`](/docs/runtime/#create-radio) from `@starwind-ui/runtime/radio`
- Runtime factory: [`createRadioGroup`](/docs/runtime/#create-radio-group) from `@starwind-ui/runtime/radio-group`

## Changelog

### v2.0.0

- Rebuilt Radio Group on Starwind Runtime for radio ownership, form participation, keyboard navigation, and value details.
- See the [Radio Primitive](/docs/primitives/radio/) and [Radio Group Primitive](/docs/primitives/radio-group/) for the underlying unstyled anatomy and behavior API.

### v1.2.6 

- Refactor tailwind variants functions into separate `variants.ts` file

### v1.2.4 

- Add `starwind:init` event listener to enable initialization of additional Radio Groups loaded after an initial page load, such as when using server islands

### v1.2.3 

- add `aria-invalid` styling

### v1.2.2 

- Removed debug logging statements

### v1.2.1 

- Add named slot "icon" to `RadioGroupItem` to enable easy icon swapping

### v1.2.0

- style and focus state updates

### v1.1.0

- Add `data-slot` attribute to enable global styling updates

### v1.0.0

- Initial release with starwind v1.7.0