Radio Group
Allows single selection from multiple options.
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-partattribute to help identify them in the DOM.
Design impact on the asChild property
The RadioGroup.Item element of the radio group is a label element. This is because the radio group is a form control
and should be associated with a label to provide context and meaning to the user. Otherwise, the HTML and accessibility
structure will be invalid.
If you need to use the
asChildproperty, make sure that thelabelelement is the direct child of theRadioGroup.Itemcomponent.
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']
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>
)
}
import { RadioGroup } from '@ark-ui/solid/radio-group'
import { Index } from 'solid-js'
export const Basic = () => {
const frameworks = ['React', 'Solid', 'Vue']
return (
<RadioGroup.Root>
<RadioGroup.Label>Framework</RadioGroup.Label>
<RadioGroup.Indicator />
<Index each={frameworks}>
{(framework) => (
<RadioGroup.Item value={framework()}>
<RadioGroup.ItemText>{framework()}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
)}
</Index>
</RadioGroup.Root>
)
}
<script setup lang="ts">
import { RadioGroup } from '@ark-ui/vue/radio-group'
import { ref } from 'vue'
const frameworks = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<RadioGroup.Root>
<RadioGroup.Label>Framework</RadioGroup.Label>
<RadioGroup.Indicator />
<RadioGroup.Item v-for="framework in frameworks" :key="framework" :value="framework">
<RadioGroup.ItemText>{{ framework }}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
</RadioGroup.Root>
</template>
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']
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>
)
}
import { RadioGroup } from '@ark-ui/solid/radio-group'
import { Index } from 'solid-js'
export const Disabled = () => {
const frameworks = ['React', 'Solid', 'Vue']
return (
<RadioGroup.Root disabled>
<RadioGroup.Label>Framework</RadioGroup.Label>
<Index each={frameworks}>
{(framework) => (
<RadioGroup.Item value={framework()}>
<RadioGroup.ItemText>{framework()}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
)}
</Index>
</RadioGroup.Root>
)
}
<script setup lang="ts">
import { RadioGroup } from '@ark-ui/vue/radio-group'
import { ref } from 'vue'
const frameworks = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<RadioGroup.Root disabled>
<RadioGroup.Label>Framework</RadioGroup.Label>
<RadioGroup.Indicator />
<RadioGroup.Item v-for="framework in frameworks" :key="framework" :value="framework">
<RadioGroup.ItemText>{{ framework }}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
</RadioGroup.Root>
</template>
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']
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>
)
}
import { RadioGroup } from '@ark-ui/solid/radio-group'
import { Index } from 'solid-js'
export const InitialValue = () => {
const frameworks = ['React', 'Solid', 'Vue']
return (
<RadioGroup.Root value="Solid">
<RadioGroup.Label>Framework</RadioGroup.Label>
<Index each={frameworks}>
{(framework) => (
<RadioGroup.Item value={framework()}>
<RadioGroup.ItemText>{framework()}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
)}
</Index>
</RadioGroup.Root>
)
}
<script setup lang="ts">
import { RadioGroup } from '@ark-ui/vue/radio-group'
import { ref } from 'vue'
const frameworks = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<RadioGroup.Root model-value="Solid">
<RadioGroup.Label>Framework</RadioGroup.Label>
<RadioGroup.Indicator />
<RadioGroup.Item v-for="framework in frameworks" :key="framework" :value="framework">
<RadioGroup.ItemText>{{ framework }}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
</RadioGroup.Root>
</template>
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']
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>
)
}
import { RadioGroup } from '@ark-ui/solid/radio-group'
import { Index } from 'solid-js'
export const OnEvent = () => {
const frameworks = ['React', 'Solid', 'Vue']
return (
<RadioGroup.Root onValueChange={(details) => console.log(details.value)}>
<RadioGroup.Label>Framework</RadioGroup.Label>
<Index each={frameworks}>
{(framework) => (
<RadioGroup.Item value={framework()}>
<RadioGroup.ItemText>{framework()}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
)}
</Index>
</RadioGroup.Root>
)
}
<script setup lang="ts">
import { RadioGroup } from '@ark-ui/vue/radio-group'
import { ref } from 'vue'
const frameworks = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<RadioGroup.Root @value-change="(details) => console.log(details.value)">
<RadioGroup.Label>Framework</RadioGroup.Label>
<RadioGroup.Indicator />
<RadioGroup.Item v-for="framework in frameworks" :key="framework" :value="framework">
<RadioGroup.ItemText>{{ framework }}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
</RadioGroup.Root>
</template>
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']
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>
</>
)
}
import { RadioGroup, useRadioGroup } from '@ark-ui/solid/radio-group'
import { Index } from 'solid-js'
export const RootProvider = () => {
const frameworks = ['React', 'Solid', 'Vue']
const radioGroup = useRadioGroup()
return (
<>
<button onClick={() => radioGroup().focus()}>Focus</button>
<RadioGroup.RootProvider value={radioGroup}>
<RadioGroup.Label>Framework</RadioGroup.Label>
<RadioGroup.Indicator />
<Index each={frameworks}>
{(framework) => (
<RadioGroup.Item value={framework()}>
<RadioGroup.ItemText>{framework()}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
)}
</Index>
</RadioGroup.RootProvider>
</>
)
}
<script setup lang="ts">
import { RadioGroup, useRadioGroup } from '@ark-ui/vue/radio-group'
import { ref } from 'vue'
const frameworks = ref(['React', 'Solid', 'Vue'])
const radioGroup = useRadioGroup()
</script>
<template>
<button @click="radioGroup.focus()">Focus</button>
<RadioGroup.RootProvider :value="radioGroup">
<RadioGroup.Label>Framework</RadioGroup.Label>
<RadioGroup.Indicator />
<RadioGroup.Item v-for="framework in frameworks" :key="framework" :value="framework">
<RadioGroup.ItemText>{{ framework }}</RadioGroup.ItemText>
<RadioGroup.ItemControl />
<RadioGroup.ItemHiddenInput />
</RadioGroup.Item>
</RadioGroup.RootProvider>
</template>
If you're using the
RootProvidercomponent, you don't need to use theRootcomponent.
API Reference
Accessibility
Complies with the Radio WAI-ARIA design pattern.
Keyboard Support
| Key | Description |
|---|---|
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. |