Ark UI Logo
Components
Radio group

Radio Group

Allows single selection from multiple options.

Loading...

Anatomy

To set up the radio group correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Examples

Learn how to use the RadioGroup component in your project. Let's take a look at the most basic example:

import { RadioGroup } from '@ark-ui/react/radio-group'

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

  return (
    <RadioGroup.Root>
      <RadioGroup.Label>Framework</RadioGroup.Label>
      <RadioGroup.Indicator />
      {frameworks.map((framework) => (
        <RadioGroup.Item key={framework} value={framework}>
          <RadioGroup.ItemText>{framework}</RadioGroup.ItemText>
          <RadioGroup.ItemControl />
          <RadioGroup.ItemHiddenInput />
        </RadioGroup.Item>
      ))}
    </RadioGroup.Root>
  )
}

Disabling the radio group

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

import { RadioGroup } from '@ark-ui/react/radio-group'

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

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

Setting the 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.

import { RadioGroup } from '@ark-ui/react/radio-group'

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

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

Listening for changes

When the radio group value changes, the onValueChange callback is invoked.

import { RadioGroup } from '@ark-ui/react/radio-group'

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

  return (
    <RadioGroup.Root onValueChange={(details) => console.log(details.value)}>
      <RadioGroup.Label>Framework</RadioGroup.Label>
      {frameworks.map((framework) => (
        <RadioGroup.Item key={framework} value={framework}>
          <RadioGroup.ItemText>{framework}</RadioGroup.ItemText>
          <RadioGroup.ItemControl />
          <RadioGroup.ItemHiddenInput />
        </RadioGroup.Item>
      ))}
    </RadioGroup.Root>
  )
}

Using the Root Provider

The RootProvider component provides a context for the radio-group. It accepts the value of the useRadio-group hook. You can leverage it to access the component state and methods from outside the radio-group.

import { RadioGroup, useRadioGroup } from '@ark-ui/react/radio-group'

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

  const radioGroup = useRadioGroup()

  return (
    <>
      <button onClick={() => radioGroup.focus()}>Focus</button>

      <RadioGroup.RootProvider value={radioGroup}>
        <RadioGroup.Label>Framework</RadioGroup.Label>
        <RadioGroup.Indicator />
        {frameworks.map((framework) => (
          <RadioGroup.Item key={framework} value={framework}>
            <RadioGroup.ItemText>{framework}</RadioGroup.ItemText>
            <RadioGroup.ItemControl />
            <RadioGroup.ItemHiddenInput />
          </RadioGroup.Item>
        ))}
      </RadioGroup.RootProvider>
    </>
  )
}

If you're using the RootProvider component, you don't need to use the Root component.

Guides

Using 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.

// 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>

Why ItemHiddenInput is required

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
// 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

Root

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
defaultValue
string

The initial value of the checked radio when rendered. Use when you don't need to control the value of the radio group.

disabled
boolean

If `true`, the radio group will be disabled

form
string

The associate form of the underlying input.

id
string

The unique identifier of the machine.

ids
Partial<{ root: string label: string indicator: string item: (value: string) => string itemLabel: (value: string) => string itemControl: (value: string) => string itemHiddenInput: (value: string) => string }>

The ids of the elements in the radio. Useful for composition.

name
string

The name of the input fields in the radio (Useful for form submission).

onValueChange
(details: ValueChangeDetails) => void

Function called once a radio is checked

orientation
'horizontal' | 'vertical'

Orientation of the radio group

readOnly
boolean

Whether the checkbox is read-only

value
string

The controlled value of the radio group

Data AttributeValue
[data-scope]radio-group
[data-part]root
[data-orientation]The orientation of the radio-group
[data-disabled]Present when disabled

Indicator

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]radio-group
[data-part]indicator
[data-disabled]Present when disabled
[data-orientation]The orientation of the indicator

ItemControl

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]radio-group
[data-part]item-control
[data-active]Present when active or pressed

ItemHiddenInput

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Item

PropDefaultType
value
string

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
disabled
boolean

invalid
boolean

ItemText

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Label

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]radio-group
[data-part]label
[data-orientation]The orientation of the label
[data-disabled]Present when disabled

RootProvider

PropDefaultType
value
UseRadioGroupReturn

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Accessibility

Complies with the Radio WAI-ARIA design pattern.

Keyboard Support

KeyDescription
Tab
Moves focus to either the checked radio item or the first radio item in the group.
Space
When focus is on an unchecked radio item, checks it.
ArrowDown
Moves focus and checks the next radio item in the group.
ArrowRight
Moves focus and checks the next radio item in the group.
ArrowUp
Moves focus to the previous radio item in the group.
ArrowLeft
Moves focus to the previous radio item in the group.