---
type: doc
title: Radio Group
description: A set of checkable buttons, known as radio buttons, where no more than one of the buttons can be checked at a time.
---

> Fulldev UI for Astro. The `@fulldev` registry in `components.json` points at `https://ui.full.dev/r/styles/{style}/{name}.json`; see [installation](/astro/docs/installation.md).

```astro title="src/components/examples/radio-group/radio-group-demo.astro"
---
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
---

<RadioGroup defaultValue="comfortable" class="w-fit">
  <div class="flex items-center gap-3">
    <RadioGroupItem value="default" id="r1" />
    <Label for="r1">Default</Label>
  </div>
  <div class="flex items-center gap-3">
    <RadioGroupItem value="comfortable" id="r2" />
    <Label for="r2">Comfortable</Label>
  </div>
  <div class="flex items-center gap-3">
    <RadioGroupItem value="compact" id="r3" />
    <Label for="r3">Compact</Label>
  </div>
</RadioGroup>
```

## Installation

```bash
npx shadcn@latest add @fulldev/radio-group
```

## Usage

```ts
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
```

```astro
<RadioGroup defaultValue="option-one" name="example">
  <div class="flex items-center gap-3">
    <RadioGroupItem value="option-one" id="option-one" />
    <Label for="option-one">Option One</Label>
  </div>
  <div class="flex items-center gap-3">
    <RadioGroupItem value="option-two" id="option-two" />
    <Label for="option-two">Option Two</Label>
  </div>
</RadioGroup>
```

`RadioGroupItem` renders a `span` with `role="radio"`. Label it with a sibling
`Label for` its `id`, or by wrapping it in a `Label`. The group creates a hidden
native radio per item, so with `name` it submits with a form.

## Composition

```text
RadioGroup
├── RadioGroupItem
└── RadioGroupItem
```

## Description

Radio group items with a description using the `Field` component.

```astro title="src/components/examples/radio-group/radio-group-description.astro"
---
import {
  Field,
  FieldContent,
  FieldDescription,
  FieldLabel,
} from "@/components/ui/field"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
---

<RadioGroup defaultValue="comfortable" class="w-fit">
  <Field orientation="horizontal">
    <RadioGroupItem value="default" id="desc-r1" />
    <FieldContent>
      <FieldLabel for="desc-r1">Default</FieldLabel>
      <FieldDescription>Standard spacing for most use cases.</FieldDescription>
    </FieldContent>
  </Field>
  <Field orientation="horizontal">
    <RadioGroupItem value="comfortable" id="desc-r2" />
    <FieldContent>
      <FieldLabel for="desc-r2">Comfortable</FieldLabel>
      <FieldDescription>More space between elements.</FieldDescription>
    </FieldContent>
  </Field>
  <Field orientation="horizontal">
    <RadioGroupItem value="compact" id="desc-r3" />
    <FieldContent>
      <FieldLabel for="desc-r3">Compact</FieldLabel>
      <FieldDescription>Minimal spacing for dense layouts.</FieldDescription>
    </FieldContent>
  </Field>
</RadioGroup>
```

## Choice Card

Use `FieldLabel` to wrap the entire `Field` for a clickable card-style selection.

```astro title="src/components/examples/radio-group/radio-group-choice-card.astro"
---
import {
  Field,
  FieldContent,
  FieldDescription,
  FieldLabel,
  FieldTitle,
} from "@/components/ui/field"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
---

<RadioGroup defaultValue="plus" class="max-w-sm">
  <FieldLabel>
    <Field as="span" orientation="horizontal">
      <FieldContent as="span">
        <FieldTitle as="span">Plus</FieldTitle>
        <FieldDescription as="span">
          For individuals and small teams.
        </FieldDescription>
      </FieldContent>
      <RadioGroupItem value="plus" id="plus-plan" />
    </Field>
  </FieldLabel>
  <FieldLabel>
    <Field as="span" orientation="horizontal">
      <FieldContent as="span">
        <FieldTitle as="span">Pro</FieldTitle>
        <FieldDescription as="span">For growing businesses.</FieldDescription>
      </FieldContent>
      <RadioGroupItem value="pro" id="pro-plan" />
    </Field>
  </FieldLabel>
  <FieldLabel>
    <Field as="span" orientation="horizontal">
      <FieldContent as="span">
        <FieldTitle as="span">Enterprise</FieldTitle>
        <FieldDescription as="span">
          For large teams and enterprises.
        </FieldDescription>
      </FieldContent>
      <RadioGroupItem value="enterprise" id="enterprise-plan" />
    </Field>
  </FieldLabel>
</RadioGroup>
```

## Fieldset

Use `FieldSet` and `FieldLegend` to group radio items with a label and description.

```astro title="src/components/examples/radio-group/radio-group-fieldset.astro"
---
import {
  Field,
  FieldDescription,
  FieldLabel,
  FieldLegend,
  FieldSet,
} from "@/components/ui/field"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
---

<FieldSet class="w-full max-w-xs">
  <FieldLegend variant="label">Subscription Plan</FieldLegend>
  <FieldDescription>
    Yearly and lifetime plans offer significant savings.
  </FieldDescription>
  <RadioGroup defaultValue="monthly">
    <Field orientation="horizontal">
      <RadioGroupItem value="monthly" id="plan-monthly" />
      <FieldLabel for="plan-monthly" class="font-normal">
        Monthly ($9.99/month)
      </FieldLabel>
    </Field>
    <Field orientation="horizontal">
      <RadioGroupItem value="yearly" id="plan-yearly" />
      <FieldLabel for="plan-yearly" class="font-normal">
        Yearly ($99.99/year)
      </FieldLabel>
    </Field>
    <Field orientation="horizontal">
      <RadioGroupItem value="lifetime" id="plan-lifetime" />
      <FieldLabel for="plan-lifetime" class="font-normal">
        Lifetime ($299.99)
      </FieldLabel>
    </Field>
  </RadioGroup>
</FieldSet>
```

## Disabled

Use the `disabled` prop on `RadioGroupItem` to disable one item, or on
`RadioGroup` to disable all items.

```astro title="src/components/examples/radio-group/radio-group-disabled.astro"
---
import { Field, FieldLabel } from "@/components/ui/field"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
---

<RadioGroup defaultValue="option2" class="w-fit">
  <Field orientation="horizontal" data-disabled>
    <RadioGroupItem value="option1" id="disabled-1" disabled />
    <FieldLabel for="disabled-1" class="font-normal">
      Disabled
    </FieldLabel>
  </Field>
  <Field orientation="horizontal">
    <RadioGroupItem value="option2" id="disabled-2" />
    <FieldLabel for="disabled-2" class="font-normal">
      Option 2
    </FieldLabel>
  </Field>
  <Field orientation="horizontal">
    <RadioGroupItem value="option3" id="disabled-3" />
    <FieldLabel for="disabled-3" class="font-normal">
      Option 3
    </FieldLabel>
  </Field>
</RadioGroup>
```

## Invalid

Use `aria-invalid` on `RadioGroupItem` and `data-invalid` on `Field` to show validation errors.

```astro title="src/components/examples/radio-group/radio-group-invalid.astro"
---
import {
  Field,
  FieldDescription,
  FieldLabel,
  FieldLegend,
  FieldSet,
} from "@/components/ui/field"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
---

<FieldSet class="w-full max-w-xs">
  <FieldLegend variant="label">Notification Preferences</FieldLegend>
  <FieldDescription>
    Choose how you want to receive notifications.
  </FieldDescription>
  <RadioGroup defaultValue="email">
    <Field orientation="horizontal" data-invalid>
      <RadioGroupItem value="email" id="invalid-email" aria-invalid="true" />
      <FieldLabel for="invalid-email" class="font-normal">
        Email only
      </FieldLabel>
    </Field>
    <Field orientation="horizontal" data-invalid>
      <RadioGroupItem value="sms" id="invalid-sms" aria-invalid="true" />
      <FieldLabel for="invalid-sms" class="font-normal">
        SMS only
      </FieldLabel>
    </Field>
    <Field orientation="horizontal" data-invalid>
      <RadioGroupItem value="both" id="invalid-both" aria-invalid="true" />
      <FieldLabel for="invalid-both" class="font-normal">
        Both Email & SMS
      </FieldLabel>
    </Field>
  </RadioGroup>
</FieldSet>
```

## RTL

```astro title="src/components/examples/radio-group/radio-group-rtl.astro"
---
import {
  Field,
  FieldContent,
  FieldDescription,
  FieldLabel,
} from "@/components/ui/field"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"

const translations = {
  en: {
    dir: "ltr",
    values: {
      default: "Default",
      defaultDescription: "Standard spacing for most use cases.",
      comfortable: "Comfortable",
      comfortableDescription: "More space between elements.",
      compact: "Compact",
      compactDescription: "Minimal spacing for dense layouts.",
    },
  },
  ar: {
    dir: "rtl",
    values: {
      default: "افتراضي",
      defaultDescription: "تباعد قياسي لمعظم حالات الاستخدام.",
      comfortable: "مريح",
      comfortableDescription: "مساحة أكبر بين العناصر.",
      compact: "مضغوط",
      compactDescription: "تباعد أدنى للتخطيطات الكثيفة.",
    },
  },
  he: {
    dir: "rtl",
    values: {
      default: "ברירת מחדל",
      defaultDescription: "ריווח סטנדרטי לרוב מקרי השימוש.",
      comfortable: "נוח",
      comfortableDescription: "יותר מקום בין האלמנטים.",
      compact: "קומפקטי",
      compactDescription: "ריווח מינימלי לפריסות צפופות.",
    },
  },
}

const { dir, values: t } = translations.ar
---

<RadioGroup defaultValue="comfortable" class="w-fit" dir={dir}>
  <Field orientation="horizontal">
    <RadioGroupItem value="default" id="r1-rtl" dir={dir} />
    <FieldContent>
      <FieldLabel for="r1-rtl" dir={dir}>
        {t.default}
      </FieldLabel>
      <FieldDescription dir={dir}>{t.defaultDescription}</FieldDescription>
    </FieldContent>
  </Field>
  <Field orientation="horizontal">
    <RadioGroupItem value="comfortable" id="r2-rtl" dir={dir} />
    <FieldContent>
      <FieldLabel for="r2-rtl" dir={dir}>
        {t.comfortable}
      </FieldLabel>
      <FieldDescription dir={dir}>{t.comfortableDescription}</FieldDescription>
    </FieldContent>
  </Field>
  <Field orientation="horizontal">
    <RadioGroupItem value="compact" id="r3-rtl" dir={dir} />
    <FieldContent>
      <FieldLabel for="r3-rtl" dir={dir}>
        {t.compact}
      </FieldLabel>
      <FieldDescription dir={dir}>{t.compactDescription}</FieldDescription>
    </FieldContent>
  </Field>
</RadioGroup>
```

## API Reference

Source: [`src/components/ui/radio-group`](https://github.com/fulldotdev/ui/tree/main/src/components/ui/radio-group)

Behavior comes from [`@data-slot/radio-group`](https://github.com/bejamas/data-slot/blob/main/packages/radio-group/README.md).

### RadioGroup

| Prop           | Type      | Default |
| -------------- | --------- | ------- |
| `defaultValue` | `string`  |         |
| `name`         | `string`  |         |
| `disabled`     | `boolean` | `false` |
| `readOnly`     | `boolean` | `false` |
| `required`     | `boolean` | `false` |

Listen for `radio-group:change` (`{ value }`) on the root, and dispatch
`radio-group:set` with `{ value }` to select a value from a script.

### RadioGroupItem

| Prop             | Type      | Default |
| ---------------- | --------- | ------- |
| `value`          | `string`  |         |
| `disabled`       | `boolean` | `false` |
| `indicatorClass` | `string`  |         |

## Install what this page shows

```bash
npx shadcn@latest add @fulldev/radio-group-examples
```
