---
title: Radio Group
description: "A set of checkable buttons where only one can be checked at a time."
---

```tsx
import * as stylex from '@stylexjs/stylex';

import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { space, fontSize } from '@/lib/constants.stylex';
import { colors, font } from '@/lib/tokens.stylex';

const options = ['Default', 'Comfortable', 'Compact'];

export default function RadioGroupDemo() {
  return (
    <RadioGroup defaultValue="Comfortable">
      {options.map((option) => (
        <label key={option} {...stylex.props(styles.label)}>
          <RadioGroupItem value={option} /> {option}
        </label>
      ))}
    </RadioGroup>
  );
}

const styles = stylex.create({
  label: {
    alignItems: 'center',
    color: colors.foreground,
    display: 'flex',
    fontFamily: font.sans,
    fontSize: fontSize.sm,
    gap: space.s2,
  },
});
```

## Install

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

## Usage

```tsx
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
```

## Composition

```tsx
<RadioGroup>
  <RadioGroupItem />
  <RadioGroupItem />
</RadioGroup>
```

## Description

Pair each item with `Field`, `FieldContent`, and `FieldDescription` to add helper text.

```tsx
import * as stylex from '@stylexjs/stylex';

import {
  Field,
  FieldContent,
  FieldDescription,
  FieldLabel,
} from '@/components/ui/field';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { space } from '@/lib/constants.stylex';

const plans = [
  {
    value: 'starter',
    label: 'Starter',
    description: 'Up to 5 projects and community support.',
  },
  {
    value: 'pro',
    label: 'Pro',
    description: 'Unlimited projects and priority support.',
  },
];

export default function RadioGroupDescription() {
  return (
    <RadioGroup defaultValue="starter" style={styles.group}>
      {plans.map((plan) => (
        <Field key={plan.value} orientation="horizontal">
          <RadioGroupItem
            value={plan.value}
            id={`radio-group-description-${plan.value}`}
          />
          <FieldContent>
            <FieldLabel htmlFor={`radio-group-description-${plan.value}`}>
              {plan.label}
            </FieldLabel>
            <FieldDescription>{plan.description}</FieldDescription>
          </FieldContent>
        </Field>
      ))}
    </RadioGroup>
  );
}

const styles = stylex.create({
  group: {
    gap: space.s4,
  },
});
```

## Choice card

Wrap each `Field` in `FieldLabel` for a clickable, card-style selection.

```tsx
import * as stylex from '@stylexjs/stylex';

import {
  Field,
  FieldContent,
  FieldDescription,
  FieldLabel,
  FieldTitle,
} from '@/components/ui/field';
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { space, stroke } from '@/lib/constants.stylex';
import { colors, radius } from '@/lib/tokens.stylex';

const plans = [
  {
    value: 'starter',
    label: 'Starter',
    description: 'Up to 5 projects and community support.',
  },
  {
    value: 'pro',
    label: 'Pro',
    description: 'Unlimited projects and priority support.',
  },
];

export default function RadioGroupChoiceCard() {
  return (
    <RadioGroup defaultValue="pro" style={styles.group}>
      {plans.map((plan) => (
        <Field key={plan.value} orientation="horizontal">
          {/* The label is the card, so the whole surface toggles the radio. */}
          <FieldLabel style={styles.card}>
            <RadioGroupItem value={plan.value} />
            <FieldContent>
              <FieldTitle>{plan.label}</FieldTitle>
              <FieldDescription>{plan.description}</FieldDescription>
            </FieldContent>
          </FieldLabel>
        </Field>
      ))}
    </RadioGroup>
  );
}

const styles = stylex.create({
  group: {
    gap: space.s3,
  },
  card: {
    alignItems: 'flex-start',
    borderColor: {
      default: colors.border,
      ':has([data-checked])': colors.primary,
    },
    borderRadius: radius.lg,
    borderStyle: 'solid',
    borderWidth: stroke.border,
    cursor: 'pointer',
    display: 'flex',
    gap: space.s3,
    padding: space.s4,
  },
});
```

## Disabled

Set `disabled` on the group to disable every item, or on a single `RadioGroupItem`.

```tsx
import * as stylex from '@stylexjs/stylex';

import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { space, fontSize } from '@/lib/constants.stylex';
import { colors, font } from '@/lib/tokens.stylex';

export default function RadioGroupDisabled() {
  return (
    <RadioGroup defaultValue="a" disabled>
      <label {...stylex.props(styles.label, styles.disabled)}>
        <RadioGroupItem value="a" /> Option A
      </label>
      <label {...stylex.props(styles.label, styles.disabled)}>
        <RadioGroupItem value="b" /> Option B
      </label>
    </RadioGroup>
  );
}

const styles = stylex.create({
  label: {
    alignItems: 'center',
    color: colors.foreground,
    display: 'flex',
    fontFamily: font.sans,
    fontSize: fontSize.sm,
    gap: space.s2,
  },
  disabled: {
    opacity: 0.5,
  },
});
```

## API reference

Built on [Base UI Radio](https://base-ui.com/react/components/radio). The tables below cover the props this library adds or changes — every other prop is forwarded to the underlying Base UI part; see the [Base UI Radio API reference](https://base-ui.com/react/components/radio#api-reference) for the full list.

### RadioGroup

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `any` | — | Controlled selected value. |
| `defaultValue` | `any` | — |  |
| `onValueChange` | `(value: any) => void` | — |  |
| `disabled` | `boolean` | `false` |  |
| `style` | `StyleXStyles` | — | StyleX styles merged last — always win over the component's own styles. |

### RadioGroupItem

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` *(required)* | `any` | — |  |
| `disabled` | `boolean` | `false` |  |
| `style` | `StyleXStyles` | — | StyleX styles merged last — always win over the component's own styles. |
