> ## Documentation Index
> Fetch the complete documentation index at: https://docs.twenty.com/llms.txt
> Use this file to discover all available pages before exploring further.

# RadioGroup

> Manage a single selection across a set of radio options.

export const StoryEmbed = ({storyId, title, height = 120}) => <>
    <Tabs>
      <Tab title="Light">
        <iframe title={`${title} (light)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:light`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
      <Tab title="Dark">
        <iframe title={`${title} (dark)`} src={`https://storybook.twenty.com/iframe.html?id=${storyId}&viewMode=story&globals=colorScheme:dark`} width="100%" height={height} loading="lazy" allow="clipboard-write" style={{
  border: 0
}} />
      </Tab>
    </Tabs>
    <a href={`https://storybook.twenty.com/?path=/story/${storyId}`}>
      Open in Storybook
    </a>
  </>;

`RadioGroup` coordinates the value, keyboard navigation, and form submission of its [Radio](/ui/primitives/input/radio) children.

<StoryEmbed storyId="ui-input-radiogroup--display" title="RadioGroup example" height={110} />

## Usage

### Uncontrolled state

Use `defaultValue` to set the initial billing frequency. The group owns subsequent changes.

```tsx theme={null}
import { Radio, RadioGroup } from 'twenty-ui/primitives/input';

export const BillingFrequency = () => (
  <RadioGroup
    name="billingFrequency"
    defaultValue="monthly"
    aria-label="Billing frequency"
  >
    <Radio value="monthly">Monthly</Radio>
    <Radio value="yearly">Yearly</Radio>
  </RadioGroup>
);
```

The group's `name` identifies the selected value in form submission. Give the group an accessible name as well as labeling each radio.

## Anatomy

Put each `Radio` or `Radio.Root` inside the group and associate it with a label. Use `Radio.Indicator` to compose a custom indicator. `RadioGroup` and `Radio` are separate exports.

```text theme={null}
fieldset
├── legend
└── RadioGroup
    ├── label
    │   └── Radio
    └── label
        └── Radio
```

| Part | Requirement | Purpose |
| - | - | - |
| `RadioGroup` | Required | Owns selection, keyboard navigation, and form integration. |
| `Radio` | One per option | Supplies an option with a distinct `value`. |
| `label` | Recommended for each option | Provides a visible, clickable name for its radio. |
| `fieldset`, `legend` | Optional grouping | Groups related controls under a visible heading. |

Give the group its own accessible name using `aria-label` or `aria-labelledby`. In the examples below, `aria-labelledby` connects the group to the legend. Each radio also needs its own name. Put selection props on `RadioGroup` and option values on `Radio`.

## Controlled state

Pass `value` and update it with `onValueChange` to own the same billing frequency in React state. Selection belongs to the group, not to individual radio controls.

```tsx theme={null}
import { useId, useState } from 'react';
import { Radio, RadioGroup } from 'twenty-ui/primitives/input';

export const BillingFrequency = () => {
  const labelId = useId();
  const [billingFrequency, setBillingFrequency] = useState('monthly');

  return (
    <fieldset>
      <legend id={labelId}>Billing frequency</legend>
      <RadioGroup
        name="billingFrequency"
        value={billingFrequency}
        onValueChange={setBillingFrequency}
        aria-labelledby={labelId}
      >
        <label>
          <Radio value="monthly" />
          Monthly
        </label>
        <label>
          <Radio value="yearly" />
          Yearly
        </label>
      </RadioGroup>
    </fieldset>
  );
};
```

`onValueChange` receives the next value and event details. The generic value type is inferred from the props. Use `disabled` on the group to disable every option, or on an individual radio to disable one choice. Arrow keys navigate and select enabled options; Tab moves out of the group. The installed Base UI version supports both horizontal and vertical arrow keys and does not expose an orientation prop. Use [DirectionProvider](/ui/primitives/layout/direction-provider) for right-to-left horizontal navigation. Visual row or column layout does not replace the upstream keyboard behavior.

## Native integration and event details

`RadioGroup` renders a div by default. Native props and `ref` target that element; `render` composes another element and changes the actual ref target. `inputRef` targets the representative hidden input of a child radio, using the selected enabled option or an enabled fallback. The public types include generic `RadioGroupProps`, `RadioGroupState`, `RadioGroupChangeEventReason` and `RadioGroupChangeEventDetails`.

The callback receives the original event details, including the native `event`, `reason`, `cancel()` and `allowPropagation()`. Cancel a proposed change before updating controlled state when the choice should be rejected.

Keep `name`, `form`, `required`, `disabled` and `readOnly` on the group for the existing Base UI form contract. The selected value is submitted under `name`; disabled groups are excluded and read-only groups keep their selection. `form` supports a group outside its owning form. The installed version does not restore group state automatically on native form reset. Reset controlled state from the form's `onReset` handler when your workflow requires it.

In sandboxed front components, put the group inside its owning form. The renderer forwards `required` validation and blocks explicit `form` references, which otherwise resolve across the host document.

[SegmentedControl](/ui/components/input/segmented-control) is a convenience preset assembled from these primitives for a short exclusive choice. It uses radio semantics and requires an accessible group name. Tabs and tab-panel navigation are separate controls.

## Props

The reference is generated from the public component types. Native attributes, including accessible names and event handlers, are also accepted on parts that render elements.

<ParamField body="className" type="string | ((state: RadioGroupState) => string | undefined)">
  CSS class applied to the element, or a function that
  returns a class based on the component's state.
</ParamField>

<ParamField body="defaultValue" type="TValue">
  The uncontrolled value of the radio button that should be initially selected.

  To render a controlled radio group, use the `value` prop instead.
</ParamField>

<ParamField body="disabled" type="boolean" default="false">
  Whether the component should ignore user interaction.
</ParamField>

<ParamField body="form" type="string">
  Identifies the form that owns the radio inputs.
  Useful when the radio group is rendered outside the form.
</ParamField>

<ParamField body="inputRef" type="Ref<HTMLInputElement>">
  A ref to access the hidden input element.
</ParamField>

<ParamField body="name" type="string">
  Identifies the field when a form is submitted.
</ParamField>

<ParamField body="onValueChange" type="((value: TValue, eventDetails: { reason: &#x22;none&#x22;; event: Event; cancel: () => void; allowPropagation: () => void; isCanceled: boolean; isPropagationAllowed: boolean; trigger: Element | undefined; }) => void)">
  Callback fired when the value changes.
</ParamField>

<ParamField body="readOnly" type="boolean" default="false">
  Whether the user should be unable to select a different radio button in the group.
</ParamField>

<ParamField body="render" type="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.
</ParamField>

<ParamField body="required" type="boolean" default="false">
  Whether the user must choose a value before submitting a form.
</ParamField>

<ParamField body="style" type="CSSProperties | ((state: RadioGroupState) => CSSProperties | undefined)">
  Style applied to the element, or a function that
  returns a style object based on the component's state.
</ParamField>

<ParamField body="value" type="TValue">
  The controlled value of the radio item that should be currently selected.

  To render an uncontrolled radio group, use the `defaultValue` prop instead.
</ParamField>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.