Radio
formUSWDS-derived
A custom-styled radio button with tile variant support.
Reference: USWDS documentation ↗
Variants
Checked
<div class="flex-radio">
<input class="flex-radio__input" id="r-checked" type="radio" name="test" value="yes" checked=""/>
<label class="flex-radio__label" for="r-checked">Pre-selected</label>
</div>Default
<fieldset>
<legend>Choices</legend>
<div class="flex-radio">
<input class="flex-radio__input" id="r-1" type="radio" name="choices" value="1"/>
<label class="flex-radio__label" for="r-1">Choice 1</label>
</div>
<div class="flex-radio">
<input class="flex-radio__input" id="r-2" type="radio" name="choices" value="2"/>
<label class="flex-radio__label" for="r-2">Choice 2</label>
</div>
<div class="flex-radio">
<input class="flex-radio__input" id="r-3" type="radio" name="choices" value="3"/>
<label class="flex-radio__label" for="r-3">Choice 3</label>
</div>
</fieldset>Disabled
<div class="flex-radio">
<input class="flex-radio__input" id="r-disabled" type="radio" name="test-disabled" value="no" disabled=""/>
<label class="flex-radio__label" for="r-disabled">Disabled option</label>
</div>Tile
<fieldset>
<legend>Tile radios</legend>
<div class="flex-radio" data-variant="tile">
<input class="flex-radio__input" id="r-tile-1" type="radio" name="tiles" value="1"/>
<label class="flex-radio__label" for="r-tile-1">Tile option 1</label>
</div>
<div class="flex-radio" data-variant="tile">
<input class="flex-radio__input" id="r-tile-2" type="radio" name="tiles" value="2"/>
<label class="flex-radio__label" for="r-tile-2">Tile option 2</label>
</div>
<div class="flex-radio" data-variant="tile">
<input class="flex-radio__input" id="r-tile-3" type="radio" name="tiles" value="3" checked=""/>
<label class="flex-radio__label" for="r-tile-3">Tile option 3</label>
</div>
</fieldset>Contract
Class mapping
| USWDS | Flex | Notes |
|---|---|---|
usa-radio | .flex-radio | Base radio wrapper |
usa-radio__input | .flex-radio__input | Hidden native radio input |
usa-radio__label | .flex-radio__label | Visible label with pseudo-element indicators |
usa-radio__input--tile | data-variant="tile" | Tile variant with bordered card appearance |
Verified properties
font-familyfont-sizeline-heightcolorcursorfont-weightpadding-leftpositiondisplayBehavior promises
- ○ Focus ring visible on keyboard focus
- ○ Checked state shows filled circle indicator
- ○ Disabled state prevents interaction
Source CSS
Base styles: Choice Input Label Base
/* flex-radio -- USWDS Radio Button conformance
Extends: Choice Input Label Base (base-classes.css#choice-input)
Variants: default, tile
States: checked, disabled, focus */
.flex-radio {
background-color: var(--flex-color-surface);
/* --- Tile variant --- */
&[data-variant="tile"] .flex-radio__input + .flex-radio__label {
background-color: var(--flex-color-surface);
border: 2px solid var(--flex-gray-20);
border-radius: 0.25rem;
color: var(--flex-color-text);
margin-block-start: 0.5rem;
padding: 0.75rem 1rem 0.75rem 2.5rem;
display: inherit;
}
&[data-variant="tile"]
.flex-radio__input:checked
+ .flex-radio__label {
background-color: color-mix(
in srgb,
var(--flex-color-accent) 10%,
transparent
);
border-color: var(--flex-color-accent);
}
&[data-variant="tile"]
.flex-radio__input:disabled
+ .flex-radio__label {
border-color: var(--flex-gray-10);
}
&[data-variant="tile"]
.flex-radio__input:disabled:checked
+ .flex-radio__label {
background-color: var(--flex-color-surface);
}
}
/* Visually hidden but accessible input. See flex-checkbox for why we use
physical `left`/`right` instead of logical `inset-inline-*`. */
.flex-radio__input {
position: absolute;
left: -999em;
right: auto;
}
/* Label — component-specific overrides */
.flex-radio__label {
margin-block-start: 0.75rem;
padding-inline-start: 2rem;
/* Radio circle (::before) */
&::before {
content: " ";
display: block;
position: absolute;
inset-inline-start: 0;
margin-inline-start: 2px;
margin-block-start: 0.064rem;
block-size: 1.25rem;
inline-size: 1.25rem;
border-radius: 99rem;
background-color: var(--flex-color-surface);
box-shadow: 0 0 0 2px var(--flex-color-text);
outline: 2px solid transparent;
outline-offset: 2px;
}
}
/* Checked state — filled circle with white inset ring */
.flex-radio__input:checked + .flex-radio__label::before {
background-color: var(--flex-color-accent);
box-shadow:
0 0 0 2px var(--flex-color-accent),
inset 0 0 0 2px var(--flex-color-surface);
}
/* Focus state */
.flex-radio__input:focus + .flex-radio__label::before {
outline: 0.25rem solid var(--flex-blue-vivid-40);
outline-offset: 0.25rem;
}
/* Disabled state — pseudo-element */
.flex-radio__input:disabled + .flex-radio__label::before {
background-color: var(--flex-color-surface);
box-shadow: 0 0 0 2px var(--flex-color-disabled);
}
.flex-radio__input:checked:disabled + .flex-radio__label::before {
background-color: var(--flex-color-disabled);
box-shadow:
0 0 0 2px var(--flex-color-disabled),
inset 0 0 0 2px var(--flex-color-surface);
}
A digital services project by Flexion