# Radio

Lets a user pick one option from a set of mutually exclusive choices.

## Installation

```tsx
import { Radio, RadioGroup } from "@makeplane/propel/components/radio";
import { RadioGroupFieldOption } from "@makeplane/propel/components/radio-group-field";
```
## Usage

```tsx
import { Field, FieldLabel } from "@makeplane/propel/components/field";
import { RadioGroup } from "@makeplane/propel/components/radio";
import { RadioGroupFieldOption } from "@makeplane/propel/components/radio-group-field";

export default function BasicDemo() {
  return (
    <Field name="priority">
      <FieldLabel size="lg" inset={false}>
        Priority
      </FieldLabel>
      <RadioGroup density="comfortable" defaultValue="low">
        <RadioGroupFieldOption size="lg" value="low" label="Low" />
        <RadioGroupFieldOption size="lg" value="medium" label="Medium" />
        <RadioGroupFieldOption size="lg" value="high" label="High" />
      </RadioGroup>
    </Field>
  );
}
```
## Examples

### Bare radios

Drop to the bare `Radio` when you compose your own rows; give each option an accessible name with `aria-label`. This names the control for assistive tech only — there's no visible label text, so prefer `RadioGroupFieldOption` (which renders a real, visible label) whenever the row has room for one.

```tsx
import { Radio, RadioGroup } from "@makeplane/propel/components/radio";

export default function BareRadiosDemo() {
  return (
    <RadioGroup density="comfortable" defaultValue="low" aria-label="Priority">
      <Radio value="low" aria-label="Low" />
      <Radio value="medium" aria-label="Medium" />
      <Radio value="high" aria-label="High" />
    </RadioGroup>
  );
}
```

### Field composition

The ready-made [`RadioGroupField`](/components/radio-group-field) owns the legend, options, and
helper text, so the group serializes under its `name` with no extra wiring. Its `orientation` prop
can stack the option rows vertically or arrange them in a wrapping horizontal row.

```tsx
import {
  RadioGroupField,
  RadioGroupFieldOption,
} from "@makeplane/propel/components/radio-group-field";

export default function FieldCompositionDemo() {
  return (
    <RadioGroupField
      name="priority"
      label="Priority"
      size="lg"
      density="comfortable"
      defaultValue="low"
      hint="Only one priority can be active."
    >
      <RadioGroupFieldOption value="low" label="Low" />
      <RadioGroupFieldOption value="medium" label="Medium" />
      <RadioGroupFieldOption value="high" label="High" />
    </RadioGroupField>
  );
}
```

### Density

`density` sets the row spacing: `comfortable` (8px gap) or `compact` (flush rows, e.g. a settings panel where options read like menu items).

```tsx
import {
  RadioGroupField,
  RadioGroupFieldOption,
} from "@makeplane/propel/components/radio-group-field";

export default function DensityDemo() {
  return (
    <div className="flex flex-wrap items-start gap-10">
      <RadioGroupField
        name="comfortableDensity"
        label="Comfortable density"
        size="lg"
        density="comfortable"
        defaultValue="low"
      >
        <RadioGroupFieldOption value="low" label="Comfortable" />
        <RadioGroupFieldOption value="medium" label="8px gap" />
      </RadioGroupField>
      <RadioGroupField
        name="compactDensity"
        label="Compact density"
        size="lg"
        density="compact"
        defaultValue="low"
      >
        <RadioGroupFieldOption value="low" label="Compact" />
        <RadioGroupFieldOption value="medium" label="Flush rows" />
      </RadioGroupField>
    </div>
  );
}
```

### With description

Each option can carry supporting text, announced as the radio's description.

```tsx
import {
  RadioGroupField,
  RadioGroupFieldOption,
} from "@makeplane/propel/components/radio-group-field";

export default function WithDescriptionDemo() {
  return (
    <RadioGroupField
      name="visibility"
      label="Project visibility"
      size="lg"
      density="comfortable"
      defaultValue="private"
    >
      <RadioGroupFieldOption
        value="private"
        label="Private"
        description="Only invited members can view this project."
      />
      <RadioGroupFieldOption
        value="workspace"
        label="Workspace"
        description="Everyone in the workspace can find and open it."
      />
      <RadioGroupFieldOption
        value="public"
        label="Public"
        description="Anyone with the link can view the project."
      />
    </RadioGroupField>
  );
}
```

### Disabled

`disabled` mutes the rows and blocks selection; set it on the group or on a single option.

```tsx
import {
  RadioGroupField,
  RadioGroupFieldOption,
} from "@makeplane/propel/components/radio-group-field";

export default function DisabledDemo() {
  return (
    <RadioGroupField
      name="priority"
      label="Priority"
      size="lg"
      density="comfortable"
      defaultValue="low"
      disabled
    >
      <RadioGroupFieldOption value="low" label="Low" />
      <RadioGroupFieldOption value="medium" label="Medium" />
      <RadioGroupFieldOption value="high" label="High" />
    </RadioGroupField>
  );
}
```

### Controlled

```tsx
import { Field, FieldLabel } from "@makeplane/propel/components/field";
import { RadioGroup } from "@makeplane/propel/components/radio";
import { RadioGroupFieldOption } from "@makeplane/propel/components/radio-group-field";
import * as React from "react";

export default function ControlledDemo() {
  const [priority, setPriority] = React.useState("low");

  return (
    <div className="flex flex-col gap-3">
      <Field name="priority">
        <FieldLabel size="lg" inset={false}>
          Priority
        </FieldLabel>
        <RadioGroup
          density="comfortable"
          value={priority}
          onValueChange={(value) => setPriority(String(value))}
        >
          <RadioGroupFieldOption size="lg" value="low" label="Low" />
          <RadioGroupFieldOption size="lg" value="medium" label="Medium" />
          <RadioGroupFieldOption size="lg" value="high" label="High" />
        </RadioGroup>
      </Field>
      <output className="text-body-xs-regular text-secondary">Selected: {priority}</output>
    </div>
  );
}
```
## API Reference

### Radio

The ready-made radio option: grafts Base UI's `Radio` behavior onto the styled `Radio` ring and
`RadioIndicator` dot. The 16px ring and 8px inner dot follow Figma node 1838-11057; the selected
and disabled states come from the primitive. Use `disabled` for a non-editable (read-only)
option. Must be rendered inside a `RadioGroup`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `render` | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, RadioRootState>` | — | Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |

### RadioGroup

Groups a set of `Radio` options so at most one can be selected at a time. Grafts Base UI's
radio-group behavior (single-select state + roving focus) onto the styled `RadioGroup` frame,
which owns the required row-spacing `density`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `density` (required) | `"comfortable" \| "compact"` | — | Spacing between radio options. |
| `render` | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, RadioGroupState>` | — | Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render. |
