Skip to main content

Theme config

Theme mode

Color palette

Grays

Border radii/radiuses/radiopedes/you know
Border radius
Field border radius
Button border radius
All
Components
Guides
API
Recent

Components

Radio

Use field groups to group related radio buttons. See also: Form documentation.

Full support Supported since v105. Full support Supported since v121. Full support Supported since v15.4.

Give every <input type="radio"> in the group the same name attribute. Browsers use that shared name to enforce mutual exclusivity within the group.

Legend
<fieldset class="fieldset">
<legend>Legend</legend>
<div class="field-group" role="group">
<label class="radio">
<input name="radio-group-html" type="radio" checked />
<span class="label">Radio 1</span>
</label>
<label class="radio">
<input name="radio-group-html" type="radio" />
<span class="label">Radio 2</span>
</label>
<label class="radio">
<input name="radio-group-html" type="radio" />
<span class="label">Radio 3</span>
</label>
</div>
</fieldset>

Direction

Legend
<fieldset class="fieldset">
<legend>Legend</legend>
<div class="field-group row" role="group">
<label class="radio">
<input name="radio-group-direction-html" type="radio" checked />
<span class="label">Radio 1</span>
</label>
<label class="radio">
<input name="radio-group-direction-html" type="radio" />
<span class="label">Radio 2</span>
</label>
<label class="radio">
<input name="radio-group-direction-html" type="radio" />
<span class="label">Radio 3</span>
</label>
</div>
</fieldset>

Field description

Can be placed above and below the fields.

Legend Field description above fields
Legend
Field description below fields
<fieldset class="fieldset">
<legend>Legend</legend>
<span class="field-description">Field description above fields</span>
<div class="field-group row" role="group">
<label class="radio">
<input name="radio-group-field-description-1-html" type="radio" checked />
<span class="label">Radio 1</span>
</label>
<label class="radio">
<input name="radio-group-field-description-1-html" type="radio" />
<span class="label">Radio 2</span>
</label>
<label class="radio">
<input name="radio-group-field-description-1-html" type="radio" />
<span class="label">Radio 3</span>
</label>
</div>
</fieldset>
<fieldset class="fieldset">
<legend>Legend</legend>
<div class="field-group row" role="group">
<label class="radio">
<input name="radio-group-field-description-2-html" type="radio" checked />
<span class="label">Radio 1</span>
</label>
<label class="radio">
<input name="radio-group-field-description-2-html" type="radio" />
<span class="label">Radio 2</span>
</label>
<label class="radio">
<input name="radio-group-field-description-2-html" type="radio" />
<span class="label">Radio 3</span>
</label>
</div>
<span class="field-description">Field description below fields</span>
</fieldset>

Disabled

Attach the disabled attribute to the <fieldset> element.

Legend
<fieldset class="fieldset" disabled>
<legend>Legend</legend>
<div class="field-group row" role="group">
<label class="radio">
<input name="radio-group-disabled-html" type="radio" checked />
<span class="label">Radio 1</span>
</label>
<label class="radio">
<input name="radio-group-disabled-html" type="radio" />
<span class="label">Radio 2</span>
</label>
<label class="radio">
<input name="radio-group-disabled-html" type="radio" />
<span class="label">Radio 3</span>
</label>
</div>
</fieldset>

Required

Attach the required attribute to at least one of your <input> elements.

Legend
<fieldset class="fieldset">
<legend>Legend</legend>
<div class="field-group row" role="group">
<label class="radio">
<input name="radio-group-required-html" type="radio" required />
<span class="label">Radio 1</span>
</label>
<label class="radio">
<input name="radio-group-required-html" type="radio" required />
<span class="label">Radio 2</span>
</label>
<label class="radio">
<input name="radio-group-required-html" type="radio" required />
<span class="label">Radio 3</span>
</label>
</div>
</fieldset>

Validation

Attach the data-invalid attribute to your fieldset.fieldset element

Legend
Something went wrong!
<fieldset class="fieldset" data-invalid>
<legend>Legend</legend>
<div class="field-group row" role="group">
<label class="radio">
<input name="radio-group-validation-html" type="radio" checked />
<span class="label">Radio 1</span>
</label>
<label class="radio">
<input name="radio-group-validation-html" type="radio" />
<span class="label">Radio 2</span>
</label>
<label class="radio">
<input name="radio-group-validation-html" type="radio" />
<span class="label">Radio 3</span>
</label>
</div>
<span class="end-text">Something went wrong!</span>
</fieldset>

API

Type Modifiers Default Description
Children <legend>, .legend, .fields, .end-text, checkbox, radio, switch - Supported child elements.
Direction default, .row - The orientation of the element.
Disabled [disabled] - When applied, disabled styles are shown.
Validation .critical - When applied, error styles are shown.

Browser support

Full support Supported since v105. Full support Supported since v121. Full support Supported since v15.4.

See also the full browser support guide.

Installation

See also

@layer components.root {
label.radio {
--_input-size: 1.125rem;
--_indicator-size: 50%;
align-items: center;
color: var(--text-primary);
cursor: pointer;
display: inline-grid;
gap: 0 var(--size-2);
grid-auto-columns: auto;
grid-auto-flow: column;
inline-size: fit-content;
line-height: 1.5;
transform: translateZ(0);
user-select: none;
/* Disabled */
&:has([disabled]) {
cursor: not-allowed;
opacity: 0.64;
user-select: none;
input {
cursor: not-allowed;
}
}
/* Required dot */
&:has(:invalid) {
.label:after {
color: var(--red);
content: "*";
inset: 0 -0.25ex auto auto;
position: absolute;
}
}
/* Label */
.label {
color: var(--text-primary);
font-size: var(--font-size-05);
grid-column: 2;
grid-row: 1;
padding-inline: 0 1ex;
position: relative;
}
/* End text */
:where(.end-text) {
color: var(--text-muted);
font-size: var(--font-size-0);
grid-column: 2;
grid-row: 2;
line-height: 1.5;
z-index: 1;
}
/* Stacked layout */
&.stack {
grid-auto-columns: unset;
justify-items: center;
.label {
grid-column: 1/-1;
grid-row: 2;
margin-block-start: var(--size-1);
padding-inline: 1ex;
/* Required dot */
&::after {
inset: 0 -0.25ex auto auto;
}
}
.end-text {
grid-column: 1/-1;
grid-row: 3;
}
}
/* Input */
input[type="radio"] {
appearance: none;
aspect-ratio: 1;
background-color: var(--surface-default);
block-size: var(--_input-size);
border: 1px solid var(--field-border-color);
border-radius: var(--radius-round);
box-sizing: border-box;
cursor: pointer;
display: grid;
inline-size: var(--_input-size);
margin: 0;
padding: 0;
place-items: center;
position: relative;
&:checked {
background-color: var(--primary);
border-color: var(--primary);
}
/* Dot */
&::after {
background-color: var(--primary-contrast);
block-size: var(--_indicator-size);
border-radius: var(--radius-round);
content: "";
inline-size: var(--_indicator-size);
margin: auto;
opacity: 0;
}
&:checked::after {
opacity: 1;
}
&::before {
--highlight-size: 175%;
}
}
/* Sizes */
&.small {
input[type="radio"] {
--_input-size: var(--size-3);
}
}
&.large {
input[type="radio"] {
--_input-size: var(--size-4);
}
}
/* Validation */
&[data-invalid],
&:has(:user-invalid) {
--palette-source: oklch(0.58 0.21 var(--hue-red));
:where(.end-text) {
color: var(--primary);
}
}
/* Touch devices */
@media (pointer: coarse) {
input[type="radio"] {
block-size: var(--size-4);
inline-size: var(--size-4);
}
}
@media (forced-colors: active) {
input[type="radio"] {
border: 1px solid CanvasText;
&:checked {
background-color: SelectedItem;
border-color: SelectedItem;
&::after {
background-color: SelectedItemText;
}
}
}
}
}
}
@layer components.extended {
/* Form */
:where(.form) {
display: grid;
gap: var(--size-8);
hr {
margin-block: 0;
}
}
/* Fieldset */
:where(.fieldset) {
all: unset;
border: 0;
border-radius: 0;
display: grid;
gap: var(--size-1);
margin: 0;
min-inline-size: 0;
padding: 0;
/* Legend */
:where(legend, .legend) {
all: unset;
color: var(--text-primary);
font-weight: 600;
margin-block-end: var(--size-3);
padding: 0;
&:has(+ :where(.field-description)) {
margin-block-end: 0;
}
}
/* Field description / supporting text */
:where(.field-description) {
color: var(--text-muted);
font-size: var(--font-size-05);
line-height: var(--font-lineheight-3);
&:has(+ *) {
margin-block-end: var(--size-3);
}
}
/* End text */
:where(.end-text) {
color: var(--text-muted);
font-size: var(--font-size-0);
line-height: var(--font-lineheight-3);
}
&:has(.text-field.row) {
row-gap: var(--size-7);
}
/* Disabled */
&[disabled] {
opacity: 0.64;
user-select: none;
input,
label,
.label {
cursor: not-allowed;
}
}
/* Error / validation */
&[data-invalid] {
:where(.end-text) {
color: var(--primary);
}
:where(.checkbox, .radio, .switch) {
--palette-source: oklch(0.58 0.21 var(--hue-red));
:where(.end-text) {
color: var(--primary);
}
}
:where(.switch) {
input {
border-radius: var(--radius-round);
outline: 2px solid var(--primary);
}
}
}
/* Required */
&:has(:invalid) {
:where(legend, .legend) {
padding-inline-end: 1ex;
position: relative;
&::after {
color: var(--red);
content: "*";
inset: 0 -0.25ex auto auto;
position: absolute;
}
}
}
}
/* Field group */
:where(.field-group) {
display: flex;
flex-direction: column;
gap: var(--size-4);
/* If it only has checkboxes, radios, or switches */
&:has(> :where(.checkbox, .radio, .switch)):not(:has(> :not(.checkbox, .radio, .switch))) {
gap: var(--size-2);
}
/* If it only has buttons */
&:has(.button):not(:has(*:not(.button))) {
align-items: center;
flex-direction: row;
gap: var(--size-2);
/* If it's not preceeded by an hr */
&:not(hr + &) {
margin-block-start: var(--size-4);
}
}
&+& {
margin-block-start: var(--size-5);
}
/* Directions */
&.row {
flex-direction: row;
flex-wrap: wrap;
&:has(> :where(.checkbox, .radio, .switch)) {
gap: var(--size-4);
}
}
}
}