A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.
<form>
<RadioGroup.root
id="radio-group-primitive"
class="DemoRadioGroupRoot"
default_value="default"
aria-label="View density"
>
<div style="display: flex; align-items: center;">
<RadioGroup.item class="DemoRadioGroupItem" value="default" id="radio-group-r1">
<RadioGroup.indicator class="DemoRadioGroupIndicator" />
</RadioGroup.item>
<label class="DemoLabel" for="radio-group-r1">Default</label>
</div>
<div style="display: flex; align-items: center;">
<RadioGroup.item class="DemoRadioGroupItem" value="comfortable" id="radio-group-r2">
<RadioGroup.indicator class="DemoRadioGroupIndicator" />
</RadioGroup.item>
<label class="DemoLabel" for="radio-group-r2">Comfortable</label>
</div>
<div style="display: flex; align-items: center;">
<RadioGroup.item class="DemoRadioGroupItem" value="compact" id="radio-group-r3">
<RadioGroup.indicator class="DemoRadioGroupIndicator" />
</RadioGroup.item>
<label class="DemoLabel" for="radio-group-r3">Compact</label>
</div>
</RadioGroup.root>
</form>
/* reset */
button {
all: unset;
}
.DemoRadioGroupRoot {
display: flex;
flex-direction: column;
gap: 10px;
}
.DemoRadioGroupItem {
background-color: white;
width: 25px;
height: 25px;
border-radius: 100%;
box-shadow: 0 2px 10px var(--black-a7);
}
.DemoRadioGroupItem:hover {
background-color: var(--violet-3);
}
.DemoRadioGroupItem:focus {
box-shadow: 0 0 0 2px black;
}
.DemoRadioGroupIndicator {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
position: relative;
}
.DemoRadioGroupIndicator::after {
content: "";
display: block;
width: 11px;
height: 11px;
border-radius: 50%;
background-color: var(--violet-11);
}
.DemoLabel {
color: white;
font-size: 15px;
line-height: 1;
padding-left: 15px;
}
Anatomy
Import all parts and piece them together.
<RadioGroup.root id="…">
<RadioGroup.item value="…">
<RadioGroup.indicator />
</RadioGroup.item>
</RadioGroup.root>
Anatomy
-
Root - Contains all the parts of a radio group.
-
Item - An item in the group that can be checked. Renders the interactive button and hidden input together.
-
Indicator - Renders when the radio item is checked.
-
Bubble Input - The visually hidden native input used for form submission. Available as a standalone part for custom composition.
API Reference
Root
Contains all the parts of a radio group.
Use value with on_value_change for controlled selection in LiveView:
<RadioGroup.root id="density" value={@value} on_value_change="radio_value_change">
…
</RadioGroup.root>
def handle_event("radio_value_change", %{"value" => value}, socket) do
{:noreply, assign(socket, :value, value)}
end
| Prop | Type | Default | Description |
|---|---|---|---|
default_value
|
string
|
nil
|
|
dir
|
string
|
"ltr"
|
|
disabled
|
boolean
|
false
|
|
id
|
string
|
—
|
|
loop
|
boolean
|
true
|
|
name
|
string
|
nil
|
|
on_value_change
|
string
|
nil
|
|
orientation
|
string
|
"vertical"
|
|
required
|
boolean
|
false
|
|
value
|
string
|
nil
|
default_value
string
Default
nil
dir
string
Default
"ltr"
disabled
boolean
Default
false
id
string
Default
—
loop
boolean
Default
true
name
string
Default
nil
on_value_change
string
Default
nil
orientation
string
Default
"vertical"
required
boolean
Default
false
value
string
Default
nil
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-disabled]
|
Present when disabled
|
Present when the group is disabled. |
Item
An item in the group that can be checked. Renders an interactive button and a visually hidden input for form submission.
| Prop | Type | Default | Description |
|---|---|---|---|
checked
|
boolean
|
false
|
|
disabled
|
boolean
|
false
|
|
form
|
string
|
nil
|
|
id
|
string
|
nil
|
|
name
|
string
|
nil
|
|
required
|
boolean
|
false
|
|
value
|
string
|
—
|
checked
boolean
Default
false
disabled
boolean
Default
false
form
string
Default
nil
id
string
Default
nil
name
string
Default
nil
required
boolean
Default
false
value
string
Default
—
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-state]
|
checked | unchecked
|
Reflects whether the item is selected. |
[data-disabled]
|
Present when disabled
|
Present when the item is disabled. |
Indicator
Renders when the radio item is in a checked state. Style this element directly, or use it as a wrapper for an icon, or both.
| Prop | Type | Default | Description |
|---|---|---|---|
checked
|
boolean
|
false
|
|
force_mount
|
boolean
|
false
|
checked
boolean
Default
false
force_mount
boolean
Default
false
Data attributes
| Attribute | Values | Description |
|---|---|---|
[data-state]
|
checked | unchecked
|
Reflects whether the item is selected. |
[data-disabled]
|
Present when disabled
|
Present when the item is disabled. |
Bubble Input
The visually hidden native radio input that RadioGroup.item renders by default. Use it directly when building items from lower-level parts.
| Prop | Type | Default | Description |
|---|---|---|---|
checked
|
boolean
|
false
|
|
disabled
|
boolean
|
false
|
|
form
|
string
|
nil
|
|
name
|
string
|
nil
|
|
required
|
boolean
|
false
|
|
value
|
string
|
—
|
checked
boolean
Default
false
disabled
boolean
Default
false
form
string
Default
nil
name
string
Default
nil
required
boolean
Default
false
value
string
Default
—
Examples
Decoupling the hidden input
By default, RadioGroup.item renders a visually hidden input for form submission. To recompose, move, or exclude that input, build each item from a button with data-radix-radio-group-item and a separate RadioGroup.bubble_input.
Place each bubble_input immediately after its button so the hook can sync checked state. Set name on the root; the hook propagates it to inputs.
<RadioGroup.root id="options" name="option" default_value="one">
<button type="button" role="radio" id="option-one" data-radix-radio-group-item data-value="one" class="DemoRadioGroupItem">
<RadioGroup.indicator class="DemoRadioGroupIndicator" />
</button>
<RadioGroup.bubble_input value="one" name="option" />
<button type="button" role="radio" id="option-two" data-radix-radio-group-item data-value="two" class="DemoRadioGroupItem">
<RadioGroup.indicator class="DemoRadioGroupIndicator" />
</button>
<RadioGroup.bubble_input value="two" name="option" />
<button type="button" role="radio" id="option-three" data-radix-radio-group-item data-value="three" class="DemoRadioGroupItem">
<RadioGroup.indicator class="DemoRadioGroupIndicator" />
</button>
<RadioGroup.bubble_input value="three" name="option" />
</RadioGroup.root>
Omit RadioGroup.bubble_input when you do not need form submission.
Accessibility
Adheres to the Radio Group WAI-ARIA design pattern and uses roving tabindex to manage focus movement among radio items.
Keyboard Interactions
Keyboard Interactions
| 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. |