Radio Group
Provides shared state to a series of radio buttons.
import { createUniqueId } from 'solid-js';
import { Radio } from 'base-ui-solid/radio';
import { RadioGroup } from 'base-ui-solid/radio-group';
import styles from './index.module.css';
export default function ExampleRadioGroup() {
const id = createUniqueId();
return (
<RadioGroup aria-labelledby={id} defaultValue="fuji-apple" class={styles.RadioGroup}>
<div class={styles.Caption} id={id}>
Best apple
</div>
<label class={styles.Item}>
<Radio.Root value="fuji-apple" class={styles.Radio}>
<Radio.Indicator class={styles.Indicator} />
</Radio.Root>
Fuji
</label>
<label class={styles.Item}>
<Radio.Root value="gala-apple" class={styles.Radio}>
<Radio.Indicator class={styles.Indicator} />
</Radio.Root>
Gala
</label>
<label class={styles.Item}>
<Radio.Root value="granny-smith-apple" class={styles.Radio}>
<Radio.Indicator class={styles.Indicator} />
</Radio.Root>
Granny Smith
</label>
</RadioGroup>
);
}
Usage guidelines
- Form controls must have an accessible name: It can be created using
<label>elements, or theFieldandFieldsetcomponents. See Labeling a radio group and the forms guide.
Anatomy
Import the component and assemble its parts:
import { Radio } from 'base-ui-solid/radio';
import { RadioGroup } from 'base-ui-solid/radio-group';
<RadioGroup>
<Radio.Root>
<Radio.Indicator />
</Radio.Root>
</RadioGroup>;
Examples
Labeling a radio group
Label the group with aria-labelledby and a sibling label element:
<div id="storage-type-label">Storage type</div>
<RadioGroup aria-labelledby="storage-type-label">{/* ... */}</RadioGroup>
An enclosing <label> is the simplest labeling pattern for each radio:
<label>
<Radio.Root value="ssd" />
SSD
</label>
Rendering as a native button
By default, <Radio.Root> renders a <span> element to support enclosing labels. Prefer rendering each radio as a native button when using sibling labels (for/id).
<div id="storage-type">Storage type</div>
<RadioGroup defaultValue="ssd" aria-labelledby="storage-type">
<div>
<label for="storage-type-ssd">SSD</label>
<Radio.Root value="ssd" id="storage-type-ssd" nativeButton render="button">
<Radio.Indicator />
</Radio.Root>
</div>
</RadioGroup>
Native buttons with wrapping labels are supported by using the render callback to avoid invalid HTML, so the hidden input is placed outside the label:
<div id="storage-type">Storage type</div>
<RadioGroup defaultValue="ssd" aria-labelledby="storage-type">
<Radio.Root
value="ssd"
nativeButton
render={(buttonProps) => (
<label>
<button {...buttonProps} />
SSD
</label>
)}
/>
</RadioGroup>
Form integration
Use Field and Fieldset for group labeling and form integration:
<Form>
<Field.Root name="storageType">
<Fieldset.Root render={(props) => <RadioGroup {...props} />}>
<Fieldset.Legend>Storage type</Fieldset.Legend>
<Field.Item>
<Field.Label>
<Radio.Root value="ssd" />
SSD
</Field.Label>
</Field.Item>
<Field.Item>
<Field.Label>
<Radio.Root value="hdd" />
HDD
</Field.Label>
</Field.Item>
</Fieldset.Root>
</Field.Root>
</Form>
API reference
RadioGroup
Provides shared state to a series of radio buttons.
Renders a <div> element.
namestring—
stringdefaultValueValue—
value prop instead.ValuevalueValue—
defaultValue prop instead.ValueonValueChangefunction—
((value: Value, eventDetails: RadioGroup.ChangeEventDetails) => void)formstring—
stringdisabledbooleanfalse
booleanreadOnlybooleanfalse
booleanrequiredbooleanfalse
booleaninputRefRef<HTMLInputElement>—
Ref<HTMLInputElement>classfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-disabled-—
-Attribute | Description | |
|---|---|---|
data-disabled | Present when the radio group is disabled. | |
RadioGroup.State
type RadioGroupState = {
/** Whether the user should be unable to select a different radio button in the group. */
readOnly: boolean;
/** Whether the user must tick a radio button within the group before submitting a form. */
required: boolean;
/** Whether the component should ignore user interaction. */
disabled: boolean;
/** Whether the field has been touched. */
touched: boolean;
/** Whether the field value has changed from its initial value. */
dirty: boolean;
/** Whether the field is valid. */
valid: boolean | null;
/** Whether the field has a value. */
filled: boolean;
/** Whether the field is focused. */
focused: boolean;
};RadioGroup.ChangeEventReason
type RadioGroupChangeEventReason = 'none';RadioGroup.ChangeEventDetails
type RadioGroupChangeEventDetails = {
/** The reason for the event. */
reason: 'none';
/** The native event associated with the custom event. */
event: Event;
/** Cancels Base UI from handling the event. */
cancel: () => void;
/** Allows the event to propagate in cases where Base UI will stop the propagation. */
allowPropagation: () => void;
/** Indicates whether the event has been canceled. */
isCanceled: boolean;
/** Indicates whether the event is allowed to propagate. */
isPropagationAllowed: boolean;
/** The element that triggered the event, if applicable. */
trigger: Element | undefined;
};Root
Represents the radio button itself.
Renders a <span> element and a hidden <input> beside.
value*Value—
ValuenativeButtonbooleanfalse
<button> element when replacing it
via the render prop.
Set to true if the rendered element is a native button.booleandisabledboolean—
booleanreadOnlyboolean—
booleanrequiredboolean—
booleaninputRefRef<HTMLInputElement>—
Ref<HTMLInputElement>classfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)renderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-checked-—
-data-unchecked-—
-data-disabled-—
-data-readonly-—
-data-required-—
-data-valid-—
-data-invalid-—
-data-dirty-—
-data-touched-—
-data-filled-—
-data-focused-—
-Attribute | Description | |
|---|---|---|
data-checked | Present when the radio is checked. | |
data-unchecked | Present when the radio is not checked. | |
data-disabled | Present when the radio is disabled. | |
data-readonly | Present when the radio is readonly. | |
data-required | Present when the radio is required. | |
data-valid | Present when the radio is in a valid state (when wrapped in Field.Root). | |
data-invalid | Present when the radio is in an invalid state (when wrapped in Field.Root). | |
data-dirty | Present when the radio’s value has changed (when wrapped in Field.Root). | |
data-touched | Present when the radio has been touched (when wrapped in Field.Root). | |
data-filled | Present when the radio is checked (when wrapped in Field.Root). | |
data-focused | Present when the radio is focused (when wrapped in Field.Root). | |
Root.State
type RadioRootState = {
/** Whether the radio button is currently selected. */
checked: boolean;
/** Whether the component should ignore user interaction. */
disabled: boolean;
/** Whether the user should be unable to select the radio button. */
readOnly: boolean;
/** Whether the user must choose a value before submitting a form. */
required: boolean;
/** Whether the radio button has been touched (when wrapped in Field.Root). */
touched: boolean;
/** Whether the radio button's value has changed from its initial value (when wrapped in Field.Root). */
dirty: boolean;
/** Whether the radio button is in a valid state (when wrapped in Field.Root). */
valid: boolean | null;
/** Whether the radio button has a value (when wrapped in Field.Root). */
filled: boolean;
/** Whether the radio button is focused (when wrapped in Field.Root). */
focused: boolean;
};Indicator
Indicates whether the radio button is selected.
Renders a <span> element.
classfunction—
JSX.ClassValue | ((state) => JSX.ClassValue)stylefunction—
JSX.CSSProperties | string | ((state) => JSX.CSSProperties | string | undefined)keepMountedbooleanfalse
booleanrenderfunction—
keyof JSX.IntrinsicElements | Component | ((props, state) => JSX.Element)Data attributes
data-checked-—
-data-unchecked-—
-data-disabled-—
-data-readonly-—
-data-required-—
-data-valid-—
-data-invalid-—
-data-dirty-—
-data-touched-—
-data-filled-—
-data-focused-—
-data-starting-style-—
-data-ending-style-—
-Attribute | Description | |
|---|---|---|
data-checked | Present when the radio is checked. | |
data-unchecked | Present when the radio is not checked. | |
data-disabled | Present when the radio is disabled. | |
data-readonly | Present when the radio is readonly. | |
data-required | Present when the radio is required. | |
data-valid | Present when the radio is in a valid state (when wrapped in Field.Root). | |
data-invalid | Present when the radio is in an invalid state (when wrapped in Field.Root). | |
data-dirty | Present when the radio’s value has changed (when wrapped in Field.Root). | |
data-touched | Present when the radio has been touched (when wrapped in Field.Root). | |
data-filled | Present when the radio is checked (when wrapped in Field.Root). | |
data-focused | Present when the radio is focused (when wrapped in Field.Root). | |
data-starting-style | Present when the radio indicator begins animating in. | |
data-ending-style | Present when the radio indicator is animating out. | |
Indicator.State
type RadioIndicatorState = {
/** The transition status of the component. */
transitionStatus: TransitionStatus;
/** Whether the radio button is currently selected. */
checked: boolean;
/** Whether the component should ignore user interaction. */
disabled: boolean;
/** Whether the user should be unable to select the radio button. */
readOnly: boolean;
/** Whether the user must choose a value before submitting a form. */
required: boolean;
/** Whether the radio button has been touched (when wrapped in Field.Root). */
touched: boolean;
/** Whether the radio button's value has changed from its initial value (when wrapped in Field.Root). */
dirty: boolean;
/** Whether the radio button is in a valid state (when wrapped in Field.Root). */
valid: boolean | null;
/** Whether the radio button has a value (when wrapped in Field.Root). */
filled: boolean;
/** Whether the radio button is focused (when wrapped in Field.Root). */
focused: boolean;
};