Choice card
A choice card wraps a native radio or checkbox in a card-shaped <label> —
pick-a-plan tiles, shipping options, settings. Selection, keyboard roving, and
form participation are all native; CSS marks the selected card via
:has(:checked). No JavaScript.
Basic (single-select)
Section titled “Basic (single-select)”Wrap the cards in a .re-choice-group <fieldset> with a <legend> naming
the question. Each card is a .re-choice <label> containing a visible
.re-radio control and a .re-choice__body with a title and optional
description.
<fieldset class="re-choice-group">
<legend>Plan</legend>
<label class="re-choice">
<input type="radio" class="re-radio" name="plan" value="starter" checked />
<span class="re-choice__body">
<span class="re-choice__title">Starter</span>
<span class="re-choice__description">2 projects, community support</span>
</span>
</label>
<label class="re-choice">
<input type="radio" class="re-radio" name="plan" value="pro" />
<span class="re-choice__body">
<span class="re-choice__title">Pro</span>
<span class="re-choice__description">Unlimited projects, priority support</span>
</span>
</label>
<label class="re-choice">
<input type="radio" class="re-radio" name="plan" value="team" />
<span class="re-choice__body">
<span class="re-choice__title">Team</span>
<span class="re-choice__description">Everything in Pro, plus SSO and audit logs</span>
</span>
</label>
</fieldset> Horizontal
Section titled “Horizontal”data-orientation="horizontal" on the group lays equal-width cards in a
wrapping row.
<fieldset class="re-choice-group" data-orientation="horizontal">
<legend>Billing period</legend>
<label class="re-choice">
<input type="radio" class="re-radio" name="billing" value="monthly" />
<span class="re-choice__body">
<span class="re-choice__title">Monthly</span>
<span class="re-choice__description">$12 / month</span>
</span>
</label>
<label class="re-choice">
<input type="radio" class="re-radio" name="billing" value="yearly" checked />
<span class="re-choice__body">
<span class="re-choice__title">Yearly</span>
<span class="re-choice__description">$120 / year — two months free</span>
</span>
</label>
</fieldset> Multi-select (checkboxes)
Section titled “Multi-select (checkboxes)”Swap in type="checkbox" + .re-checkbox for independent options — same
markup otherwise.
<fieldset class="re-choice-group">
<legend>Add-ons</legend>
<label class="re-choice">
<input type="checkbox" class="re-checkbox" name="addons" value="backups" checked />
<span class="re-choice__body">
<span class="re-choice__title">Daily backups</span>
<span class="re-choice__description">Retained for 30 days</span>
</span>
</label>
<label class="re-choice">
<input type="checkbox" class="re-checkbox" name="addons" value="monitoring" />
<span class="re-choice__body">
<span class="re-choice__title">Uptime monitoring</span>
<span class="re-choice__description">Alerts by email and webhook</span>
</span>
</label>
</fieldset> Disabled option
Section titled “Disabled option”Disable the input; the card follows via :has(:disabled).
<fieldset class="re-choice-group">
<legend>Region</legend>
<label class="re-choice">
<input type="radio" class="re-radio" name="region" value="eu" checked />
<span class="re-choice__body">
<span class="re-choice__title">Europe (Frankfurt)</span>
</span>
</label>
<label class="re-choice">
<input type="radio" class="re-radio" name="region" value="ap" disabled />
<span class="re-choice__body">
<span class="re-choice__title">Asia Pacific (Tokyo)</span>
<span class="re-choice__description">Coming soon</span>
</span>
</label>
</fieldset> Accessibility
Section titled “Accessibility”- The control stays visible. The card doesn’t hide the radio/checkbox behind styling — the native control carries the checked state, so assistive tech, Windows High Contrast, and muscle memory all get the standard control. The accent border + tint on the selected card is an enhancement, never the only cue (WCAG 1.4.1).
- Name comes from the label. The wrapping
<label>gives the input its accessible name from the visible title and description; the<legend>names the group. Keep both. - Focus ring on the card. Keyboard focus rings the whole card rather than
the small control, so the focused option is obvious at a glance. Under
forced colors the selected card’s border is re-established with the system
Highlightcolor. - Arrow keys work natively. Radio groups rove with arrow keys; checkboxes Tab individually — both are browser behavior, nothing to configure.
See the accessibility guide for the project-wide stance.