# Radio Group

A set of options where only one can be selected.

Source: [radio-group.tsx](https://github.com/jakejarvis/jarvis-ui/blob/main/src/components/ui/radio-group.tsx)

```tsx
import { FieldItem, FieldLabel, FieldLegend, FieldSet } from "@/components/ui/field";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";

export default function RadioGroupBasic() {
  return (
    <FieldSet>
      <FieldLegend variant="label">Density</FieldLegend>
      <RadioGroup defaultValue="comfortable">
        <FieldItem>
          <RadioGroupItem value="compact" />
          <FieldLabel>Compact</FieldLabel>
        </FieldItem>
        <FieldItem>
          <RadioGroupItem value="comfortable" />
          <FieldLabel>Comfortable</FieldLabel>
        </FieldItem>
        <FieldItem>
          <RadioGroupItem value="spacious" />
          <FieldLabel>Spacious</FieldLabel>
        </FieldItem>
      </RadioGroup>
    </FieldSet>
  );
}
```

## Installation

Add the registry, once per project:

```bash
npx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json
```

Then add the component:

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

## Usage

Pair each item with a label in a `FieldItem`, and name the group with a `FieldSet` and
`FieldLegend`.

```tsx
import { FieldItem, FieldLabel, FieldLegend, FieldSet } from "@/components/ui/field";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";

export function ThemePicker() {
  return (
    <FieldSet>
      <FieldLegend variant="label">Theme</FieldLegend>
      <RadioGroup defaultValue="system">
        <FieldItem>
          <RadioGroupItem value="light" />
          <FieldLabel>Light</FieldLabel>
        </FieldItem>
        <FieldItem>
          <RadioGroupItem value="dark" />
          <FieldLabel>Dark</FieldLabel>
        </FieldItem>
        <FieldItem>
          <RadioGroupItem value="system" />
          <FieldLabel>System</FieldLabel>
        </FieldItem>
      </RadioGroup>
    </FieldSet>
  );
}
```

Without a visible legend, give the `RadioGroup` an `aria-label` instead.

## Composition

- `RadioGroup`
  - `RadioGroupItem`

## Examples

### With descriptions

Wrap the label in a `FieldContent` with a `FieldDescription` when an option needs explaining.

```tsx
import {
  FieldContent,
  FieldDescription,
  FieldItem,
  FieldLabel,
  FieldLegend,
  FieldSet,
} from "@/components/ui/field";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";

export default function RadioGroupWithDescriptions() {
  return (
    <FieldSet className="w-full max-w-sm">
      <FieldLegend variant="label">Visibility</FieldLegend>
      <RadioGroup defaultValue="private">
        <FieldItem>
          <RadioGroupItem value="public" />
          <FieldContent>
            <FieldLabel>Public</FieldLabel>
            <FieldDescription>Anyone with the link can view it.</FieldDescription>
          </FieldContent>
        </FieldItem>
        <FieldItem>
          <RadioGroupItem value="private" />
          <FieldContent>
            <FieldLabel>Private</FieldLabel>
            <FieldDescription>Only people you invite can view it.</FieldDescription>
          </FieldContent>
        </FieldItem>
      </RadioGroup>
    </FieldSet>
  );
}
```

### Disabled

Set `disabled` on an item, or on the `RadioGroup` to disable all of them.

```tsx
import {
  FieldContent,
  FieldDescription,
  FieldItem,
  FieldLabel,
  FieldLegend,
  FieldSet,
} from "@/components/ui/field";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";

export default function RadioGroupDisabled() {
  return (
    <FieldSet>
      <FieldLegend variant="label">Layout</FieldLegend>
      <RadioGroup defaultValue="list">
        <FieldItem>
          <RadioGroupItem value="list" />
          <FieldLabel>List</FieldLabel>
        </FieldItem>
        <FieldItem>
          <RadioGroupItem value="board" />
          <FieldLabel>Board</FieldLabel>
        </FieldItem>
        <FieldItem>
          <RadioGroupItem value="timeline" disabled />
          <FieldContent>
            <FieldLabel>Timeline</FieldLabel>
            <FieldDescription>Not available on small screens.</FieldDescription>
          </FieldContent>
        </FieldItem>
      </RadioGroup>
    </FieldSet>
  );
}
```

### Choice cards

Put the item and its `FieldContent` inside the `FieldLabel` to make the whole card clickable.

```tsx
import {
  FieldContent,
  FieldDescription,
  FieldItem,
  FieldLabel,
  FieldLegend,
  FieldSet,
  FieldTitle,
} from "@/components/ui/field";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";

const plans = [
  { value: "starter", name: "Starter", description: "Up to 3 projects and 5 members." },
  { value: "team", name: "Team", description: "Unlimited projects and 25 members." },
  { value: "enterprise", name: "Enterprise", description: "SSO, audit logs and priority support." },
];

export default function RadioGroupChoiceCards() {
  return (
    <FieldSet className="w-full max-w-sm">
      <FieldLegend variant="label">Plan</FieldLegend>
      <RadioGroup defaultValue="team">
        {plans.map((plan) => (
          <FieldItem key={plan.value}>
            <FieldLabel>
              <FieldContent>
                <FieldTitle>{plan.name}</FieldTitle>
                <FieldDescription>{plan.description}</FieldDescription>
              </FieldContent>
              <RadioGroupItem value={plan.value} />
            </FieldLabel>
          </FieldItem>
        ))}
      </RadioGroup>
    </FieldSet>
  );
}
```

### Invalid

Wrap the group in a `Field`, set `invalid` on it, and explain the problem with a `FieldError`.

```tsx
import {
  Field,
  FieldError,
  FieldItem,
  FieldLabel,
  FieldLegend,
  FieldSet,
} from "@/components/ui/field";
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";

export default function RadioGroupInvalid() {
  return (
    <Field invalid className="w-fit">
      <FieldSet>
        <FieldLegend variant="label">Shipping speed</FieldLegend>
        <RadioGroup>
          <FieldItem>
            <RadioGroupItem value="standard" />
            <FieldLabel>Standard</FieldLabel>
          </FieldItem>
          <FieldItem>
            <RadioGroupItem value="express" />
            <FieldLabel>Express</FieldLabel>
          </FieldItem>
        </RadioGroup>
      </FieldSet>
      <FieldError>Choose a shipping speed.</FieldError>
    </Field>
  );
}
```

## Props

| Part | Extends |
| --- | --- |
| `RadioGroup` | [`RadioGroup`](https://base-ui.com/react/components/radio-group#api-reference) |
| `RadioGroupItem` | [`Radio.Root`](https://base-ui.com/react/components/radio#root) |

The tables leave out `className`, `style` and `render`. Parts built on Base UI take them as its [styling](https://base-ui.com/react/handbook/styling) and [composition](https://base-ui.com/react/handbook/composition) guides describe.

### RadioGroup

| Prop             | Type                                                                  | Description                                                                                                                                           |
| ---------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `disabled?`      | `boolean`                                                             | Whether the component should ignore user interaction. Default: `false`                                                                                |
| `readOnly?`      | `boolean`                                                             | Whether the user should be unable to select a different radio button in the group. Default: `false`                                                   |
| `required?`      | `boolean`                                                             | Whether the user must choose a value before submitting a form. Default: `false`                                                                       |
| `name?`          | `string`                                                              | Identifies the field when a form is submitted.                                                                                                        |
| `form?`          | `string`                                                              | Identifies the form that owns the radio inputs. Useful when the radio group is rendered outside the form.                                             |
| `value?`         | `any`                                                                 | The controlled value of the radio item that should be currently selected. To render an uncontrolled radio group, use the `defaultValue` prop instead. |
| `defaultValue?`  | `any`                                                                 | The uncontrolled value of the radio button that should be initially selected. To render a controlled radio group, use the `value` prop instead.       |
| `onValueChange?` | `((value: any, eventDetails: RadioGroup.ChangeEventDetails) => void)` | Callback fired when the value changes.                                                                                                                |
| `inputRef?`      | `React.Ref<HTMLInputElement>`                                         | A ref to access the hidden input element.                                                                                                             |

### RadioGroupItem

| Prop            | Type                          | Description                                                                                                                                                                   |
| --------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `value`         | `any`                         | The unique identifying value of the radio in a group.                                                                                                                         |
| `disabled?`     | `boolean`                     | Whether the component should ignore user interaction.                                                                                                                         |
| `required?`     | `boolean`                     | Whether the user must choose a value before submitting a form.                                                                                                                |
| `readOnly?`     | `boolean`                     | Whether the user should be unable to select the radio button.                                                                                                                 |
| `inputRef?`     | `React.Ref<HTMLInputElement>` | A ref to access the hidden input element.                                                                                                                                     |
| `nativeButton?` | `boolean`                     | Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `true` if the rendered element is a native button. Default: `false` |
