Radio Group
A set of radio buttons where no more than one can be checked at a time.
Installation
Install the following dependencies:
Set up the token layer and the StyleX compiler, if you have not already. See
Installation, and paste states.ts and
state-styles.ts from the same page. The radio group imports both. The examples caption
their buttons with a Label or a
Field.
Paste field-state.ts from the same installation page.
Copy and paste the following code into your project.
Update the import paths to match your project setup.
Usage
RadioGroup is a grid that fills its container and stacks its children. Match
each label's htmlFor to its button's id, or wrap the button in the label.
Selected value
Use defaultValue for an uncontrolled group, or value and onValueChange to
control it. value is the value of the selected RadioGroupItem, which can
be any type.
Description
Put a Field around each button and a FieldContent beside it to add a line
of helper text under the label.
Standard spacing for most use cases.
More space between elements.
Minimal spacing for dense layouts.
Choice card
Wrap a whole Field in a FieldLabel to turn the option into a card, and pass
checked to mark the selected one.
FieldLabel cannot read the button's state, so checked is a prop you set from
the same value you give RadioGroup. That makes the card a controlled group.
Fieldset
Use Fieldset and FieldsetLegend to caption the group as a whole, and give the
group a name to submit it with a form.
Disabled
Set disabled on Field to disable its control and dim its label, or on a bare control directly.
Invalid
Set invalid on Field to style its control, or aria-invalid on a bare control. The examples show both.
API reference
Pass render to replace a part's element or compose it with another component.
Both parts wrap the Base UI RadioGroup and Radio primitives and accept
their props. See the Base UI reference.
Each part also takes xstyle and className.
RadioGroup
| Prop | Type | Default |
|---|---|---|
value | Value | — |
defaultValue | Value | — |
onValueChange | (value: Value, details) => void | — |
name | string | — |
disabled | boolean | false |
readOnly | boolean | false |
required | boolean | false |
form | string | — |
xstyle | StyleXStyles | — |
className | string | — |
The root is a <div role="radiogroup">. Arrow keys move between the buttons
and select as they go, and the group is one tab stop.
RadioGroupItem
| Prop | Type | Default |
|---|---|---|
value | Value | — |
disabled | boolean | false |
readOnly | boolean | false |
required | boolean | false |
aria-invalid | boolean | — |
id | string | — |
inputRef | Ref<HTMLInputElement> | — |
xstyle | StyleXStyles | — |
style | CSSProperties | — |
className | string | — |
The item is a <span role="radio">. Base UI renders a hidden <input> beside
it that carries id, name and value. A label's htmlFor and a form
submission reach the item through that input.
radioGroupStyles
The style maps behind the component. Spread them onto any element.
| Key | What it is |
|---|---|
group | The grid and its gap |
item | The circle: size, border width, hit area |
key | The raised key's colours at a choice's size |
surface | The raised shadow, kept through focus |
checked | The glossy primary fill and inverted dot |
disabled | The dimmed, non-interactive state |
invalid | The destructive border and ring |
item has no colour and no focus ring. Everything else comes from states
in theme/states.ts, the same key the checkbox uses. Merge key, then
states.focusRing, then surface. Merge invalid before checked, so a
selected invalid button keeps the primary fill and shows only the destructive
ring.
Data attributes
| Attribute | On | Effect |
|---|---|---|
data-slot="radio-group" | the root | Targets the grid from a parent |
data-slot="radio-group-item" | a button | Targets the circle |
data-slot="radio-group-indicator" | the dot | Targets the animated indicator |
data-checked, data-unchecked | item, dot | Base UI writes them |
data-disabled, data-readonly, data-required | root, item | Base UI writes them |
data-starting-style, data-ending-style | the dot | Base UI writes them while the dot enters or leaves |