Radio buttons
Radio buttons pick one option from a short list, with every option in view. A radio set groups them under one name, so choosing one clears the others and a form submits only the chosen value. It lays them out in a column or, for two or three short options, a row. Each set below holds a different choice, so pick one.
Reference docs
Choosing a selection control
Four components capture a choice in a form. Each suits a different job:
- Checkbox: one or more options picked from a short list, or a single yes to confirm, such as "I agree to the terms".
- Switch: a setting that takes effect the moment it is flipped, such as Wi-Fi or dark mode.
- Radio buttons: exactly one option from a short list shown in full, such as delivery speed.
- Select: exactly one option from a longer list kept closed until opened, such as country.
Two jobs belong elsewhere. A choice made by clicking a compact tag, such as filtering results, is a filter chip, and a two-state setting in a toolbar is a toggle button.
Built in
- Radio buttons that share a name act as one group with no script, and a radio set writes
onto each radio for you, generating one when none exists, so two unnamed sets never merge into one group.name - The checked radio holds the group's one Tab stop, and the arrow keys move and check.
- A checked radio submits its
under its name, andvalue on any radio requires the whole group.required - A column or a row of options with
, 36 pixels apart.horizontal - The radio set is the radio group assistive technology announces, named by the
aria-labeloraria-labelledbyyou give it. - Radios inside a disabled fieldset disable themselves; no
on each one.disabled - The touch target is at least 48 by 48 pixels even though the circle paints smaller (
).touch-target - Each radio's label is the default slot's content, so a radio needs no separate label element.
Using radio buttons well
- Put each set of options in one radio set, and give the set a visible label that names the choice.
- Give every option a visible label after its control, in the radio's default slot.
- Stack the options in a column by default. Keep
for two or three short options, because a row never wraps.horizontal - Select a sensible default when one exists. With none, nothing is chosen until the user picks, and a form can still submit that state.
These rules follow Material 3 Expressive's guidance for radio buttons, on material.io.
Groups
Put radio buttons in a radio set, cw-radio-setcheckedchange, which the demo uses to report the choice.
Layout
horizontal
Group label
Give the radio set an aria-labelledby holding the id of the element that names the choice, which then names the group. Each radio button keeps its own label as well: the set labels the group, never the options.
Forms and names
name
The set's valuevalue under the group name, and a form that holds no checked radio submits nothing for the group.
Requiring a choice
A checked radio submits its valuenamenamenamerequired
The demo wires a form as a page would. The preview cannot submit it, so the button reports from its own click, and the form's reset button returns the group to its authored state.
Touch target
touch-targetoverflow
With overflowwrappernone
Disabled
disabled<fieldset> is disabled too, and its disabled
Properties
| Property | Attribute | Type | Description |
|---|---|---|---|
compareWith | (a: TItem, b: TItem) => boolean | Decides whether two values are the same, in place of the default matching and of valueKey. | |
horizontal | horizontal | booleandefault false | Lays the radios out in a row instead of a column. See Layout. |
name | name | string | The name every radio in the set submits under, and groups by. Set it here rather than on each radio. Left empty, the set gives every radio the first name one of them carries, and generates a name only when none carries one. See Forms and names, Requiring a choice. |
value | value | TItem | The checked radio's value, or null when no radio is checked. Setting it checks the radio whose value matches; a value no radio holds is kept, with no radio checked, until a radio holding it arrives. When several radios hold the value and none of them is checked, the first of them is checked. See Forms and names, Requiring a choice. |
valueKey | value-key | string | The field that identifies an object value: two objects match when this field holds the same value on both. |
name
Slots
| Slot | Description |
|---|---|
| (default) | The radio buttons to be displayed. |
Only direct cw-radio
Events
| Event | Type | Detail | Description |
|---|---|---|---|
input | InputEvent | — | Fired when the user changes the selection. It bubbles and is composed. |
change | SelectionChangeEvent | SelectionChangeEventDetail<TItem> | Fired when the set's value changes other than by setting value: the user's selection, or code checking or unchecking one of its radios. It bubbles, as do the radios' own change events, so a listener on the set checks event.target to tell them apart. It bubbles. |
Props
| Prop | Type | Description |
|---|---|---|
compareWith | (a: TItem, b: TItem) => boolean | Decides whether two values are the same, in place of the default matching and of valueKey. |
horizontal | booleandefault false | Lays the radios out in a row instead of a column. See Layout. |
name | string | The name every radio in the set submits under, and groups by. Set it here rather than on each radio. Left empty, the set gives every radio the first name one of them carries, and generates a name only when none carries one. See Forms and names, Requiring a choice. |
value | TItem | The checked radio's value, or null when no radio is checked. Setting it checks the radio whose value matches; a value no radio holds is kept, with no radio checked, until a radio holding it arrives. When several radios hold the value and none of them is checked, the first of them is checked. See Forms and names, Requiring a choice. |
valueKey | string | The field that identifies an object value: two objects match when this field holds the same value on both. |
name
Children
| Child | Description |
|---|---|
children | The radio buttons to be displayed. |
Only direct cw-radio
Events
| Prop | Argument | Description |
|---|---|---|
onInput | React.ChangeEvent<HTMLInputElement> | Fired when the user changes the selection. It bubbles and is composed. |
onChange | SelectionChangeEvent<TItem> | Fired when the set's value changes other than by setting value: the user's selection, or code checking or unchecking one of its radios. It bubbles, as do the radios' own change events, so a listener on the set checks event.target to tell them apart. It bubbles. Its detail carries value and values. |
Parameters
| Parameter | Type | Description |
|---|---|---|
Horizontal | bool?default false | Lays the radios out in a row instead of a column. See Layout. |
Name | string? | The name every radio in the set submits under, and groups by. Set it here rather than on each radio. Left empty, the set gives every radio the first name one of them carries, and generates a name only when none carries one. See Forms and names, Requiring a choice. |
Value | TItem | The checked radio's value, or null when no radio is checked. Setting it checks the radio whose value matches; a value no radio holds is kept, with no radio checked, until a radio holding it arrives. When several radios hold the value and none of them is checked, the first of them is checked. See Forms and names, Requiring a choice. |
ValueExpression | Expression<Func<TItem>>? | Gets or sets an expression that identifies the bound value. |
name
Render fragments
| Parameter | Type | Description |
|---|---|---|
ChildContent | RenderFragment? | The radio buttons to be displayed. |
Only direct cw-radio
Event callbacks
| Parameter | Type | Description |
|---|---|---|
OnInput | EventCallback<ChangeEventArgs> | Fired when the user changes the selection. It bubbles and is composed. |
OnChange | EventCallback<SelectionChangeEventArgs<TItem>> | Fired when the set's Value changes other than by setting Value: the user's selection, or code checking or unchecking one of its radios. It bubbles, as do the radios' own change events, so a listener on the set checks event.target to tell them apart. It bubbles. Its detail carries Value and values. |
Inputs
| Input | Type | Description |
|---|---|---|
compareWith | (a: TItem, b: TItem) => boolean | Decides whether two values are the same, in place of the default matching and of valueKey. |
horizontal | booleandefault false | Lays the radios out in a row instead of a column. See Layout. |
name | string | The name every radio in the set submits under, and groups by. Set it here rather than on each radio. Left empty, the set gives every radio the first name one of them carries, and generates a name only when none carries one. See Forms and names, Requiring a choice. |
value | TItem | The checked radio's value, or null when no radio is checked. Setting it checks the radio whose value matches; a value no radio holds is kept, with no radio checked, until a radio holding it arrives. When several radios hold the value and none of them is checked, the first of them is checked. See Forms and names, Requiring a choice. |
valueKey | string | The field that identifies an object value: two objects match when this field holds the same value on both. |
name
Content projection
| Content | Description |
|---|---|
content with no slot | The radio buttons to be displayed. |
Only direct cw-radio
Outputs
| Output | Event | Description |
|---|---|---|
cwInput | InputEvent | Fired when the user changes the selection. It bubbles and is composed. |
cwChange | SelectionChangeEvent | Fired when the set's value changes other than by setting value: the user's selection, or code checking or unchecking one of its radios. It bubbles, as do the radios' own change events, so a listener on the set checks event.target to tell them apart. It bubbles. Its detail carries value and values. |
Props
| Prop | Type | Description |
|---|---|---|
compareWith | (a: TItem, b: TItem) => boolean | Decides whether two values are the same, in place of the default matching and of valueKey. |
horizontal | booleandefault false | Lays the radios out in a row instead of a column. See Layout. |
name | string | The name every radio in the set submits under, and groups by. Set it here rather than on each radio. Left empty, the set gives every radio the first name one of them carries, and generates a name only when none carries one. See Forms and names, Requiring a choice. |
value | TItem | The checked radio's value, or null when no radio is checked. Setting it checks the radio whose value matches; a value no radio holds is kept, with no radio checked, until a radio holding it arrives. When several radios hold the value and none of them is checked, the first of them is checked. See Forms and names, Requiring a choice. |
valueKey | string | The field that identifies an object value: two objects match when this field holds the same value on both. |
name
Slots
| Slot | Description |
|---|---|
default | The radio buttons to be displayed. |
Only direct cw-radio
Events
| Event | Type | Description |
|---|---|---|
input | InputEvent | Fired when the user changes the selection. It bubbles and is composed. |
change | SelectionChangeEvent | Fired when the set's value changes other than by setting value: the user's selection, or code checking or unchecking one of its radios. It bubbles, as do the radios' own change events, so a listener on the set checks event.target to tell them apart. It bubbles. Its detail carries value and values. |
Props
| Prop | Type | Description |
|---|---|---|
compareWith | (a: TItem, b: TItem) => boolean | Decides whether two values are the same, in place of the default matching and of valueKey. |
horizontal | booleandefault false | Lays the radios out in a row instead of a column. See Layout. |
name | string | The name every radio in the set submits under, and groups by. Set it here rather than on each radio. Left empty, the set gives every radio the first name one of them carries, and generates a name only when none carries one. See Forms and names, Requiring a choice. |
value | TItem | The checked radio's value, or null when no radio is checked. Setting it checks the radio whose value matches; a value no radio holds is kept, with no radio checked, until a radio holding it arrives. When several radios hold the value and none of them is checked, the first of them is checked. See Forms and names, Requiring a choice. |
valueKey | string | The field that identifies an object value: two objects match when this field holds the same value on both. |
name
Snippets
| Snippet | Description |
|---|---|
children | The radio buttons to be displayed. |
Only direct cw-radio
Events
| Prop | Type | Description |
|---|---|---|
onInput | InputEvent | Fired when the user changes the selection. It bubbles and is composed. |
onChange | SelectionChangeEvent | Fired when the set's value changes other than by setting value: the user's selection, or code checking or unchecking one of its radios. It bubbles, as do the radios' own change events, so a listener on the set checks event.target to tell them apart. It bubbles. Its detail carries value and values. |
Properties
| Property | Attribute | Type | Description |
|---|---|---|---|
checked | checked | boolean | Whether the radio is the selected one in its group. A user's selection updates it. See Groups. |
disabled | disabled | boolean | Whether the element is disabled. Also reads true while a disabled <fieldset> contains it. See Disabled. |
formread-only | HTMLFormElement | The form the component belongs to, or null when it has none. | |
labelsread-only | NodeList | The <label> elements associated with the element. | |
name | name | string | The name the radio's value is submitted under while it is checked. Radios that share a name in the same page or component form a group, in which checking one unchecks the others. See Forms and names, Requiring a choice. |
required | required | booleandefault false | Whether or not the radio is required. If any radio is required in a group, all radios are implicitly required. See Requiring a choice. |
tabIndex | tabindex | number | The element's position in the tab order: 0 puts it in the order, and -1 leaves it out while script can still focus it. A group, such as a set of tabs, manages it for its members. |
touchTarget | touch-targetnone, overflow, wrapper | TouchTargetTouchTarget.None, .Overflow, .Wrapperdefault TouchTarget.Overflow, from the style configuration | The area that takes a touch, at least 48 by 48 pixels and centered on the component. overflow extends it past the component without changing the component's layout size, wrapper makes the component take up the whole area in the layout, and none limits it to the component's own size. See Touch target. |
validationMessageread-only | string | The message describing why the element is invalid, or an empty string when it is valid. | |
validityread-only | ValidityState | The element's ValidityState. | |
value | value | unknowndefault on | The value the radio stands for. A radio set's value is the checked radio's value. It can be any value when set from code; the attribute gives a string. A form receives it as a string while the radio is checked. See Forms and names, Requiring a choice. |
willValidateread-only | boolean | Whether the element takes part in constraint validation. False while it is disabled or read-only. |
A form reset returns each radio to its authored checked
Slots
| Slot | Description |
|---|---|
| (default) | The label content. |
Events
| Event | Type | Detail | Description |
|---|---|---|---|
input | InputEvent | — | Dispatched after change when the user selects the radio with a click or Space, including when it is already selected. An arrow key moves the selection without it. It bubbles and is composed. |
change | Event | — | Dispatched when the user selects the radio with a click, Space or an arrow key, and when another radio in its group is selected and unchecks it. A click also fires it when the radio is already selected, and before input. Setting checked from code does not fire it on that radio. It bubbles. |
Methods
| Method | Returns | Description |
|---|---|---|
checkValidity() | boolean | Checks the element's validity and returns true if it is valid. If not, it dispatches an invalid event; nothing changes on screen. |
reportValidity() | boolean | Checks the element's validity and returns true if it is valid. If not, it dispatches a cancelable invalid event and, unless a listener cancels it, shows validationMessage as the field's error text and focuses the field. |
setCustomValidity(error: string) | void | Sets a custom validation message, which makes the element invalid. An empty string clears it. |
Props
| Prop | Type | Description |
|---|---|---|
checked | boolean | Whether the radio is the selected one in its group. A user's selection updates it. See Groups. |
disabled | boolean | Whether the element is disabled. Also reads true while a disabled <fieldset> contains it. See Disabled. |
formread-only (ref) | HTMLFormElement | The form the component belongs to, or null when it has none. |
labelsread-only (ref) | NodeList | The <label> elements associated with the element. |
name | string | The name the radio's value is submitted under while it is checked. Radios that share a name in the same page or component form a group, in which checking one unchecks the others. See Forms and names, Requiring a choice. |
required | booleandefault false | Whether or not the radio is required. If any radio is required in a group, all radios are implicitly required. See Requiring a choice. |
tabIndex | number | The element's position in the tab order: 0 puts it in the order, and -1 leaves it out while script can still focus it. A group, such as a set of tabs, manages it for its members. |
touchTarget | TouchTargetTypeTouchTarget.None, .Overflow, .Wrapperdefault TouchTarget.Overflow, from the style configuration | The area that takes a touch, at least 48 by 48 pixels and centered on the component. overflow extends it past the component without changing the component's layout size, wrapper makes the component take up the whole area in the layout, and none limits it to the component's own size. See Touch target. |
validationMessageread-only (ref) | string | The message describing why the element is invalid, or an empty string when it is valid. |
validityread-only (ref) | ValidityState | The element's ValidityState. |
value | unknowndefault on | The value the radio stands for. A radio set's value is the checked radio's value. It can be any value when set from code; the attribute gives a string. A form receives it as a string while the radio is checked. See Forms and names, Requiring a choice. |
willValidateread-only (ref) | boolean | Whether the element takes part in constraint validation. False while it is disabled or read-only. |
A form reset returns each radio to its authored checked
Children
| Child | Description |
|---|---|
children | The label content. |
Events
| Prop | Argument | Description |
|---|---|---|
onInput | React.ChangeEvent<HTMLInputElement> | Dispatched after change when the user selects the radio with a click or Space, including when it is already selected. An arrow key moves the selection without it. It bubbles and is composed. |
onChange | React.ChangeEvent<HTMLInputElement> | Dispatched when the user selects the radio with a click, Space or an arrow key, and when another radio in its group is selected and unchecks it. A click also fires it when the radio is already selected, and before input. Setting checked from code does not fire it on that radio. It bubbles. |
Methods
Call these on the element the ref holds.
| Method | Returns | Description |
|---|---|---|
checkValidity() | boolean | Checks the element's validity and returns true if it is valid. If not, it dispatches an invalid event; nothing changes on screen. |
reportValidity() | boolean | Checks the element's validity and returns true if it is valid. If not, it dispatches a cancelable invalid event and, unless a listener cancels it, shows validationMessage as the field's error text and focuses the field. |
setCustomValidity(error: string) | void | Sets a custom validation message, which makes the element invalid. An empty string clears it. |
Parameters
| Parameter | Type | Description |
|---|---|---|
Checked | bool? | Whether the radio is the selected one in its group. A user's selection updates it. See Groups. |
Disabled | bool? | Whether the element is disabled. Also reads true while a disabled <fieldset> contains it. See Disabled. |
Name | string? | The name the radio's Value is submitted under while it is checked. Radios that share a name in the same page or component form a group, in which checking one unchecks the others. See Forms and names, Requiring a choice. |
Required | bool?default false | Whether or not the radio is required. If any radio is required in a group, all radios are implicitly required. See Requiring a choice. |
TabIndex | int? | The element's position in the tab order: 0 puts it in the order, and -1 leaves it out while script can still focus it. A group, such as a set of tabs, manages it for its members. |
TouchTarget | TouchTarget?TouchTarget.None, .Overflow, .Wrapperdefault TouchTarget.Overflow, from the style configuration | The area that takes a touch, at least 48 by 48 pixels and centered on the component. overflow extends it past the component without changing the component's layout size, wrapper makes the component take up the whole area in the layout, and none limits it to the component's own size. See Touch target. |
Value | TItemdefault on | The value the radio stands for. A radio set's Value is the checked radio's value. It can be any value when set from code; the attribute gives a string. A form receives it as a string while the radio is checked. See Forms and names, Requiring a choice. |
A form reset returns each radio to its authored checked
Render fragments
| Parameter | Type | Description |
|---|---|---|
ChildContent | RenderFragment? | The label content. |
Event callbacks
| Parameter | Type | Description |
|---|---|---|
OnInput | EventCallback<ChangeEventArgs> | Dispatched after change when the user selects the radio with a click or Space, including when it is already selected. An arrow key moves the selection without it. It bubbles and is composed. |
OnChange | EventCallback<ChangeEventArgs> | Dispatched when the user selects the radio with a click, Space or an arrow key, and when another radio in its group is selected and unchecks it. A click also fires it when the radio is already selected, and before input. Setting Checked from code does not fire it on that radio. It bubbles. |
Inputs
| Input | Type | Description |
|---|---|---|
checked | boolean | Whether the radio is the selected one in its group. A user's selection updates it. See Groups. |
disabled | boolean | Whether the element is disabled. Also reads true while a disabled <fieldset> contains it. See Disabled. |
name | string | The name the radio's value is submitted under while it is checked. Radios that share a name in the same page or component form a group, in which checking one unchecks the others. See Forms and names, Requiring a choice. |
required | booleandefault false | Whether or not the radio is required. If any radio is required in a group, all radios are implicitly required. See Requiring a choice. |
tabIndex | number | The element's position in the tab order: 0 puts it in the order, and -1 leaves it out while script can still focus it. A group, such as a set of tabs, manages it for its members. |
touchTarget | TouchTargetTypeTouchTarget.None, .Overflow, .Wrapperdefault TouchTarget.Overflow, from the style configuration | The area that takes a touch, at least 48 by 48 pixels and centered on the component. overflow extends it past the component without changing the component's layout size, wrapper makes the component take up the whole area in the layout, and none limits it to the component's own size. See Touch target. |
value | unknowndefault on | The value the radio stands for. A radio set's value is the checked radio's value. It can be any value when set from code; the attribute gives a string. A form receives it as a string while the radio is checked. See Forms and names, Requiring a choice. |
A form reset returns each radio to its authored checked
Content projection
| Content | Description |
|---|---|
content with no slot | The label content. |
Outputs
| Output | Event | Description |
|---|---|---|
cwInput | InputEvent | Dispatched after change when the user selects the radio with a click or Space, including when it is already selected. An arrow key moves the selection without it. It bubbles and is composed. |
cwChange | Event | Dispatched when the user selects the radio with a click, Space or an arrow key, and when another radio in its group is selected and unchecks it. A click also fires it when the radio is already selected, and before input. Setting checked from code does not fire it on that radio. It bubbles. |
Props
| Prop | Type | Description |
|---|---|---|
checked | boolean | Whether the radio is the selected one in its group. A user's selection updates it. See Groups. |
disabled | boolean | Whether the element is disabled. Also reads true while a disabled <fieldset> contains it. See Disabled. |
name | string | The name the radio's value is submitted under while it is checked. Radios that share a name in the same page or component form a group, in which checking one unchecks the others. See Forms and names, Requiring a choice. |
required | booleandefault false | Whether or not the radio is required. If any radio is required in a group, all radios are implicitly required. See Requiring a choice. |
tabIndex | number | The element's position in the tab order: 0 puts it in the order, and -1 leaves it out while script can still focus it. A group, such as a set of tabs, manages it for its members. |
touchTarget | TouchTargetTypeTouchTarget.None, .Overflow, .Wrapperdefault TouchTarget.Overflow, from the style configuration | The area that takes a touch, at least 48 by 48 pixels and centered on the component. overflow extends it past the component without changing the component's layout size, wrapper makes the component take up the whole area in the layout, and none limits it to the component's own size. See Touch target. |
value | unknowndefault on | The value the radio stands for. A radio set's value is the checked radio's value. It can be any value when set from code; the attribute gives a string. A form receives it as a string while the radio is checked. See Forms and names, Requiring a choice. |
A form reset returns each radio to its authored checked
Slots
| Slot | Description |
|---|---|
default | The label content. |
Events
| Event | Type | Description |
|---|---|---|
input | InputEvent | Dispatched after change when the user selects the radio with a click or Space, including when it is already selected. An arrow key moves the selection without it. It bubbles and is composed. |
change | Event | Dispatched when the user selects the radio with a click, Space or an arrow key, and when another radio in its group is selected and unchecks it. A click also fires it when the radio is already selected, and before input. Setting checked from code does not fire it on that radio. It bubbles. |
Props
| Prop | Type | Description |
|---|---|---|
checked | boolean | Whether the radio is the selected one in its group. A user's selection updates it. See Groups. |
disabled | boolean | Whether the element is disabled. Also reads true while a disabled <fieldset> contains it. See Disabled. |
name | string | The name the radio's value is submitted under while it is checked. Radios that share a name in the same page or component form a group, in which checking one unchecks the others. See Forms and names, Requiring a choice. |
required | booleandefault false | Whether or not the radio is required. If any radio is required in a group, all radios are implicitly required. See Requiring a choice. |
tabIndex | number | The element's position in the tab order: 0 puts it in the order, and -1 leaves it out while script can still focus it. A group, such as a set of tabs, manages it for its members. |
touchTarget | TouchTargetTypeTouchTarget.None, .Overflow, .Wrapperdefault TouchTarget.Overflow, from the style configuration | The area that takes a touch, at least 48 by 48 pixels and centered on the component. overflow extends it past the component without changing the component's layout size, wrapper makes the component take up the whole area in the layout, and none limits it to the component's own size. See Touch target. |
value | unknowndefault on | The value the radio stands for. A radio set's value is the checked radio's value. It can be any value when set from code; the attribute gives a string. A form receives it as a string while the radio is checked. See Forms and names, Requiring a choice. |
A form reset returns each radio to its authored checked
Snippets
| Snippet | Description |
|---|---|
children | The label content. |
Events
| Prop | Type | Description |
|---|---|---|
onInput | InputEvent | Dispatched after change when the user selects the radio with a click or Space, including when it is already selected. An arrow key moves the selection without it. It bubbles and is composed. |
onChange | Event | Dispatched when the user selects the radio with a click, Space or an arrow key, and when another radio in its group is selected and unchecks it. A click also fires it when the radio is already selected, and before input. Setting checked from code does not fire it on that radio. It bubbles. |
A value is what the token defaults to; selecting it copies the token's name.
Tokens
| Token | Value |
|---|---|
--ct-radio-set-horizontal-spacing | 36px --ct-radio-set-horizontal-spacing |
--ct-radio-set-vertical-spacing | 36px --ct-radio-set-vertical-spacing |
A value is what the token defaults to; selecting it copies the token's name.
Tokens
| Token | Value |
|---|---|
--ct-radio-container-end-end-radius | same as --ct-radio-container-radius --ct-radio-container-end-end-radius |
--ct-radio-container-end-start-radius | same as --ct-radio-container-radius --ct-radio-container-end-start-radius |
--ct-radio-container-radius | 2px --ct-radio-container-radius |
--ct-radio-container-start-end-radius | same as --ct-radio-container-radius --ct-radio-container-start-end-radius |
--ct-radio-container-start-start-radius | same as --ct-radio-container-radius --ct-radio-container-start-start-radius |
--ct-radio-disabled-label-text-color | --ct-sys-color-on-surface --ct-radio-disabled-label-text-color |
--ct-radio-disabled-label-text-opacity | 0.38 --ct-radio-disabled-label-text-opacity |
--ct-radio-disabled-selected-icon-color | --ct-sys-color-on-surface --ct-radio-disabled-selected-icon-color |
--ct-radio-disabled-selected-icon-opacity | 0.38 --ct-radio-disabled-selected-icon-opacity |
--ct-radio-disabled-unselected-icon-color | --ct-sys-color-on-surface --ct-radio-disabled-unselected-icon-color |
--ct-radio-disabled-unselected-icon-opacity | 0.38 --ct-radio-disabled-unselected-icon-opacity |
--ct-radio-focus-icon-color | --ct-sys-color-on-surface --ct-radio-focus-icon-color |
--ct-radio-hover-icon-color | --ct-sys-color-on-surface --ct-radio-hover-icon-color |
--ct-radio-hover-state-layer-color | --ct-sys-color-on-surface --ct-radio-hover-state-layer-color |
--ct-radio-hover-state-layer-opacity | --ct-sys-state-hover-state-layer-opacity --ct-radio-hover-state-layer-opacity |
--ct-radio-icon-color | --ct-sys-color-on-surface-variant --ct-radio-icon-color |
--ct-radio-icon-size | 20px --ct-radio-icon-size |
--ct-radio-label-gap | 21px --ct-radio-label-gap |
--ct-radio-label-text-color | --ct-sys-color-on-surface --ct-radio-label-text-color |
--ct-radio-label-text-font | --ct-sys-typescale-label-large-font --ct-radio-label-text-font |
--ct-radio-label-text-line-height | --ct-sys-typescale-label-large-line-height --ct-radio-label-text-line-height |
--ct-radio-label-text-size | --ct-sys-typescale-label-large-size --ct-radio-label-text-size |
--ct-radio-label-text-weight | --ct-sys-typescale-label-large-weight --ct-radio-label-text-weight |
--ct-radio-pressed-icon-color | --ct-sys-color-on-surface --ct-radio-pressed-icon-color |
--ct-radio-pressed-state-layer-color | --ct-sys-color-primary --ct-radio-pressed-state-layer-color |
--ct-radio-pressed-state-layer-opacity | --ct-sys-state-pressed-state-layer-opacity --ct-radio-pressed-state-layer-opacity |
--ct-radio-selected-focus-icon-color | --ct-sys-color-primary --ct-radio-selected-focus-icon-color |
--ct-radio-selected-hover-icon-color | --ct-sys-color-primary --ct-radio-selected-hover-icon-color |
--ct-radio-selected-hover-state-layer-color | --ct-sys-color-primary --ct-radio-selected-hover-state-layer-color |
--ct-radio-selected-hover-state-layer-opacity | --ct-sys-state-hover-state-layer-opacity --ct-radio-selected-hover-state-layer-opacity |
--ct-radio-selected-icon-color | --ct-sys-color-primary --ct-radio-selected-icon-color |
--ct-radio-selected-pressed-icon-color | --ct-sys-color-primary --ct-radio-selected-pressed-icon-color |
--ct-radio-selected-pressed-state-layer-color | --ct-sys-color-on-surface --ct-radio-selected-pressed-state-layer-color |
--ct-radio-selected-pressed-state-layer-opacity | --ct-sys-state-pressed-state-layer-opacity --ct-radio-selected-pressed-state-layer-opacity |
--ct-radio-state-layer-size | 40px --ct-radio-state-layer-size |
Names and states
A radio set is a radiogroup and each radio button a radio, announced with its checked state; together they follow the WAI-ARIA Authoring Practices: Radio Group pattern.
- The radio set is the group, and takes its name from the
aria-labelledbyoraria-labelyou give it. Pointaria-labelledbyat a visible label for the choice; the set has no label property and no slot for one. - The group announces its orientation as horizontal in a row and vertical in a column.
- Each radio button names itself from its slotted text or its
aria-label. Give every radio a visible label, or anaria-labelwhere its spoken name matters; the set labels the group, not the options. is announced as the checked state, andcheckedaria-labelis the only ARIA attribute to set on a radio.- A radio announces itself as a radio and the set announces the group, so set no role on either. A radio outside a set draws no group of its own.
- The set's
is the checked radio's value, and it is announced through that radio. The set has no disabled state of its own: disable each radio, or set itvaluerequired, on its own.
Keyboard and focus
| Key | Action |
|---|---|
| Tab | Enters the group at its one Tab stop: the checked radio, or the first enabled radio when none is checked. |
| Shift+Tab | Leaves the group the same way. |
| Arrow keys | Move to the next or previous enabled radio and check it, wrapping at the ends. |
| Space | Checks the focused radio. |
Tab and Shift+Tab are the browser's own; the radios handle Space and the arrow keys, and the set adds none. Home and End do nothing.
- All four arrow keys work in both orientations: Up and Down work in a row; Left and Right work in a column.
- Each radio draws a focus ring on keyboard focus only.
- A disabled radio is never the Tab stop, and the arrow keys skip it. A disabled radio that is checked takes the whole group out of the Tab order, and so does disabling every radio.
Pointer and touch
- Each radio has a touch target of at least 48 by 48 pixels by default, above the 24 by 24 pixel minimum of WCAG 2.5.8, whatever size the circle paints. The 36-pixel gap between radios keeps the targets apart.
shrinks the touch area to the circle, which no longer guarantees that minimum. The Touch target example shows all three values.none
Display settings
- In forced colors, a radio paints its circle in
CanvasText, and a disabled radio inGrayText. Hover draws a round 2 pixelButtonTextring, and press a 4 pixel one. - Under a reduced-motion preference, a radio drops its selection transitions and animation.
- In right-to-left text, the Left arrow moves to the next radio and the Right arrow to the previous one. Nothing else mirrors.
Standards
With its defaults, radio buttons in a radio set meet three WCAG 2.2 success criteria:
Three more depend on how you use them, each with the one thing you do: