# Radio Group

URL: https://ark-ui.com/docs/components/radio-group
LLM: https://ark-ui.com/llms.txt/components/radio-group

Allows single selection from multiple options.

---



## Anatomy



```tsx
<RadioGroup.Root>
  <RadioGroup.Label />
  <RadioGroup.Indicator />
  <RadioGroup.Item>
    <RadioGroup.ItemControl />
    <RadioGroup.ItemText />
    <RadioGroup.ItemHiddenInput />
  </RadioGroup.Item>
</RadioGroup.Root>
```

## Examples

```tsx
import { RadioGroup } from '@ark-ui/react/radio-group'
import styles from 'styles/radio-group.module.css'

export const Basic = () => {
  const frameworks = ['React', 'Solid', 'Vue']

  return (
    <RadioGroup.Root className={styles.Root} defaultValue="React">
      <RadioGroup.Label className={styles.Label}>Framework</RadioGroup.Label>
      {frameworks.map((framework) => (
        <RadioGroup.Item className={styles.Item} key={framework} value={framework}>
          <RadioGroup.ItemControl className={styles.ItemControl} />
          <RadioGroup.ItemText className={styles.ItemText}>{framework}</RadioGroup.ItemText>
          <RadioGroup.ItemHiddenInput />
        </RadioGroup.Item>
      ))}
    </RadioGroup.Root>
  )
}
```

### Initial Value

To set the radio group's initial value, set the `defaultValue` prop to the value of the radio item to be selected by
default.

```tsx
import { RadioGroup } from '@ark-ui/react/radio-group'
import styles from 'styles/radio-group.module.css'

export const InitialValue = () => {
  const frameworks = ['React', 'Solid', 'Vue']

  return (
    <RadioGroup.Root className={styles.Root} defaultValue="Solid">
      <RadioGroup.Label className={styles.Label}>Framework</RadioGroup.Label>
      {frameworks.map((framework) => (
        <RadioGroup.Item className={styles.Item} key={framework} value={framework}>
          <RadioGroup.ItemControl className={styles.ItemControl} />
          <RadioGroup.ItemText className={styles.ItemText}>{framework}</RadioGroup.ItemText>
          <RadioGroup.ItemHiddenInput />
        </RadioGroup.Item>
      ))}
    </RadioGroup.Root>
  )
}
```

### Controlled

For a controlled Radio Group, the state is managed using the `value` prop, and updates when the `onValueChange` event
handler is called:

```tsx
import { RadioGroup } from '@ark-ui/react/radio-group'
import { useState } from 'react'
import styles from 'styles/radio-group.module.css'

export const Controlled = () => {
  const frameworks = ['React', 'Solid', 'Vue']
  const [value, setValue] = useState<string | null>(null)

  return (
    <RadioGroup.Root className={styles.Root} value={value} onValueChange={(e) => setValue(e.value)}>
      <RadioGroup.Label className={styles.Label}>Framework</RadioGroup.Label>
      {frameworks.map((framework) => (
        <RadioGroup.Item className={styles.Item} key={framework} value={framework}>
          <RadioGroup.ItemControl className={styles.ItemControl} />
          <RadioGroup.ItemText className={styles.ItemText}>{framework}</RadioGroup.ItemText>
          <RadioGroup.ItemHiddenInput />
        </RadioGroup.Item>
      ))}
    </RadioGroup.Root>
  )
}
```

### Root Provider

An alternative way to control the radio group is to use the `RootProvider` component and the `useRadioGroup` hook. This
way you can access the state and methods from outside the component.

```tsx
import { RadioGroup, useRadioGroup } from '@ark-ui/react/radio-group'
import button from 'styles/button.module.css'
import styles from 'styles/radio-group.module.css'

export const RootProvider = () => {
  const frameworks = ['React', 'Solid', 'Vue']
  const radioGroup = useRadioGroup({ defaultValue: 'React' })

  return (
    <div className="stack">
      <RadioGroup.RootProvider className={styles.Root} value={radioGroup}>
        <RadioGroup.Label className={styles.Label}>Framework</RadioGroup.Label>
        {frameworks.map((framework) => (
          <RadioGroup.Item className={styles.Item} key={framework} value={framework}>
            <RadioGroup.ItemControl className={styles.ItemControl} />
            <RadioGroup.ItemText className={styles.ItemText}>{framework}</RadioGroup.ItemText>
            <RadioGroup.ItemHiddenInput />
          </RadioGroup.Item>
        ))}
      </RadioGroup.RootProvider>

      <button className={button.Root} onClick={() => radioGroup.setValue('Solid')}>
        Set to Solid
      </button>
    </div>
  )
}
```

### Disabled

To make a radio group disabled, set the `disabled` prop to `true`.

```tsx
import { RadioGroup } from '@ark-ui/react/radio-group'
import styles from 'styles/radio-group.module.css'

export const Disabled = () => {
  const frameworks = ['React', 'Solid', 'Vue']

  return (
    <RadioGroup.Root className={styles.Root} defaultValue="React" disabled>
      <RadioGroup.Label className={styles.Label}>Framework</RadioGroup.Label>
      {frameworks.map((framework) => (
        <RadioGroup.Item className={styles.Item} key={framework} value={framework}>
          <RadioGroup.ItemControl className={styles.ItemControl} />
          <RadioGroup.ItemText className={styles.ItemText}>{framework}</RadioGroup.ItemText>
          <RadioGroup.ItemHiddenInput />
        </RadioGroup.Item>
      ))}
    </RadioGroup.Root>
  )
}
```

## Guides

### asChild

The `RadioGroup.Item` component renders as a `label` element by default. This ensures proper form semantics and
accessibility, as radio groups are form controls that require labels to provide meaningful context for users.

When using the `asChild` prop, you must **render a `label` element** as the direct child of `RadioGroup.Item` to
maintain valid HTML structure and accessibility compliance.

```tsx
// INCORRECT usage ❌
<RadioGroup.Item asChild>
  <div>
    <RadioGroup.ItemHiddenInput />
    <RadioGroup.ItemText>
      <RadioGroup.ItemControl />
    </RadioGroup.ItemText>
  </div>
</RadioGroup.Item>

// CORRECT usage ✅
<RadioGroup.Item asChild>
  <label>
    <RadioGroup.ItemHiddenInput />
    <RadioGroup.ItemText>
      <RadioGroup.ItemControl />
    </RadioGroup.ItemText>
  </label>
</RadioGroup.Item>
```

### Hidden Input

The `RadioGroup.ItemHiddenInput` component renders a hidden HTML input element that enables proper form submission and
integration with native form behaviors. This component is essential for the radio group to function correctly as it:

- Provides the underlying input element that browsers use for form submission
- Enables integration with form libraries and validation systems
- Ensures the radio group works with native form reset functionality

```tsx
// INCORRECT usage ❌
<RadioGroup.Item>
  <RadioGroup.ItemText>
    <RadioGroup.ItemControl />
  </RadioGroup.ItemText>
</RadioGroup.Item>

// CORRECT usage ✅
<RadioGroup.Item>
  <RadioGroup.ItemHiddenInput />
  <RadioGroup.ItemText>
    <RadioGroup.ItemControl />
  </RadioGroup.ItemText>
</RadioGroup.Item>
```

## API Reference

### Props

### Root

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

**`defaultValue`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The initial value of the checked radio when rendered.
Use when you don't need to control the value of the radio group.

**`disabled`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: If `true`, the radio group will be disabled

**`form`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The associate form of the underlying input.

**`id`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The unique identifier of the machine.

**`ids`**
Type: `Partial<{
  root: string
  label: string
  indicator: string
  item: (value: string) => string
  itemLabel: (value: string) => string
  itemControl: (value: string) => string
  itemHiddenInput: (value: string) => string
}>`
Required: false
Default Value: `undefined`
Description: The ids of the elements in the radio. Useful for composition.

**`invalid`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: If `true`, the radio group is marked as invalid.

**`name`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The name of the input fields in the radio
(Useful for form submission).

**`onValueChange`**
Type: `(details: ValueChangeDetails) => void`
Required: false
Default Value: `undefined`
Description: Function called once a radio is checked

**`orientation`**
Type: `'horizontal' | 'vertical'`
Required: false
Default Value: `undefined`
Description: Orientation of the radio group

**`readOnly`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Whether the radio group is read-only

**`required`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: If `true`, the radio group is marked as required.

**`value`**
Type: `string`
Required: false
Default Value: `undefined`
Description: The controlled value of the radio group

#### Data Attributes

**`data-scope`**: radio-group
**`data-part`**: root
**`data-orientation`**: The orientation of the radio-group
**`data-disabled`**: Present when disabled
**`data-invalid`**: Present when invalid
**`data-required`**: Present when required

### Indicator

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: radio-group
**`data-part`**: indicator
**`data-disabled`**: Present when disabled
**`data-orientation`**: The orientation of the indicator

### ItemControl

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: radio-group
**`data-part`**: item-control
**`data-active`**: Present when active or pressed

### ItemHiddenInput

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### Item

#### Props

**`value`**
Type: `string`
Required: true
Default Value: `undefined`
Description: undefined

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

**`disabled`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: undefined

**`invalid`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: undefined

### ItemText

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### Label

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: radio-group
**`data-part`**: label
**`data-orientation`**: The orientation of the label
**`data-disabled`**: Present when disabled
**`data-invalid`**: Present when invalid
**`data-required`**: Present when required

### RootProvider

#### Props

**`value`**
Type: `UseRadioGroupReturn`
Required: true
Default Value: `undefined`
Description: undefined

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### Context

**API:**

| Property | Type | Description |
|----------|------|-------------|
| `value` | `string | null` | The current value of the radio group |
| `setValue` | `(value: string) => void` | Function to set the value of the radio group |
| `clearValue` | `VoidFunction` | Function to clear the value of the radio group |
| `focus` | `VoidFunction` | Function to focus the radio group |
| `getItemState` | `(props: ItemProps) => ItemState` | Returns the state details of a radio input |


## Accessibility

Complies with the [Radio WAI-ARIA design pattern](https://www.w3.org/WAI/ARIA/apg/patterns/radio/).

### Keyboard Support

**`Tab`**
Description: Moves focus to either the checked radio item or the first radio item in the group.

**`Space`**
Description: When focus is on an unchecked radio item, checks it.

**`ArrowDown`**
Description: Moves focus and checks the next radio item in the group.

**`ArrowRight`**
Description: Moves focus and checks the next radio item in the group.

**`ArrowUp`**
Description: Moves focus to the previous radio item in the group.

**`ArrowLeft`**
Description: Moves focus to the previous radio item in the group.