BetaComponent · since 0.4.0
A native radio button with its label: pick exactly one option from a short, visible list.
Pick this part
Pick c-radio for
- Exactly one choice from 2 to 6 options that people should compare side by side.
- A choice where seeing every option helps the decision, such as a delivery speed or a plan.
Pick another part for
- Any number of options may be chosen: use
c-checkbox. - An on/off setting that applies immediately: use
c-toggle. - More than about 7 options: use a
c-inputon a<select>.
Build it
- Start with
<div>and addclass="c-radio". - Add the required parts:
c-radio__input,c-radio__label. - Add the parts you need:
c-radio__hint. - Set state on the native control, never with data-state:
:checked,:disabled.
Show markup 19 lines
<fieldset class="c-form-field">
<legend class="c-form-field__label">Delivery speed</legend>
<div class="l-stack l-stack--sm">
<div class="c-radio">
<input class="c-radio__input" type="radio" id="delivery-standard" name="delivery" value="standard" checked aria-describedby="delivery-standard-hint">
<label class="c-radio__label" for="delivery-standard">Standard</label>
<p class="c-radio__hint" id="delivery-standard-hint">3 to 5 working days, free.</p>
</div>
<div class="c-radio">
<input class="c-radio__input" type="radio" id="delivery-next" name="delivery" value="next-day" aria-describedby="delivery-next-hint">
<label class="c-radio__label" for="delivery-next">Next day</label>
<p class="c-radio__hint" id="delivery-next-hint">Order by 4pm, £4.99.</p>
</div>
<div class="c-radio">
<input class="c-radio__input" type="radio" id="delivery-same" name="delivery" value="same-day" disabled>
<label class="c-radio__label" for="delivery-same">Same day (not available in your area)</label>
</div>
</div>
</fieldset>
Check your build
Each piece that doesn't fit was run through mcss-lite validate when this page was built. The output below is real.
Fits
Put the group in a fieldset with a legend, and give every radio the same name.
Show markup 14 lines
<fieldset class="c-form-field">
<legend class="c-form-field__label">Delivery speed</legend>
<div class="l-stack l-stack--sm">
<div class="c-radio">
<input class="c-radio__input" type="radio" id="speed-standard" name="speed" value="standard" checked aria-describedby="speed-standard-hint">
<label class="c-radio__label" for="speed-standard">Standard</label>
<p class="c-radio__hint" id="speed-standard-hint">3 to 5 working days, free.</p>
</div>
<div class="c-radio">
<input class="c-radio__input" type="radio" id="speed-next" name="speed" value="next-day">
<label class="c-radio__label" for="speed-next">Next day</label>
</div>
</div>
</fieldset>
validate: 0 issues
Doesn't fit
Don't mark a group error with aria-invalid on each radio; ARIA doesn't allow it there. Put the error on the fieldset.
<fieldset class="c-form-field" data-state="error">
<legend class="c-form-field__label">Delivery speed</legend>
<div class="c-radio">
<input class="c-radio__input" type="radio" id="speed-x" name="speed-x" value="standard">
<label class="c-radio__label" for="speed-x">Standard</label>
</div>
</fieldset>
validate
- warning data-state="error" on a <fieldset> also needs aria-describedby pointing at the c-form-field__error message.
[state-pair]
Spec sheet
Apply to <div>
| Class | On | What it does |
|---|---|---|
c-radio__input required | <input> | The native control. Carries every state: checked, disabled. |
c-radio__label required | <label> | The visible label, linked with for/id. Clicking it toggles the control and pads the hit area. |
c-radio__hint | <p> <div> <span> | Optional one-line hint under the label, linked with aria-describedby. |
| State | Meaning | Pair it with |
|---|---|---|
:checked | Selected: an ink stud seated in the ring. | Use the checked attribute, never data-state. |
:disabled | Cannot be chosen. Dashed ring, ghosted label. | Use the disabled attribute, and say nearby why it is unavailable. |
Show tokens 4
| Token | Value (light / dark) |
|---|---|
--checkbox-size | 1.5rem |
--checkbox-background | #ffffff / #14294d |
--checkbox-border | #1a1d20 / #a9bacb |
--radio-dot | #1a1d20 / #e6edf4 |
Accessibility
- Keep native <input type="radio"> elements sharing one name: the browser handles arrow keys and single selection.
- Wrap the group in fieldset + legend so the question is read with every option.
- Link hints with aria-describedby on the input.
| Key | What it does |
|---|---|
| Tab | Moves focus into the group, to the checked radio (or the first), and out again. |
| Arrow keys | Move to and select the next or previous radio. |
| Space | Selects the focused radio if nothing is selected. |
Wording
- The legend asks the question; each label is a short answer in sentence case.
- Use a hint for the detail that decides the choice: price, time, consequence.