Radio
hc-radio is applied to a standard <input type="radio">. The
underlying input keeps every native behaviour — arrow keys move between
members of a group sharing the same name, the selected value
participates in form submission, screen readers announce position
(“3 of 5”) within the group. Only the rendering is replaced via
appearance: none.
Basic HTML
Section titled “Basic HTML”Free
Pro
Team
<label class="hc-radio-label"> <input class="hc-radio" type="radio" name="plan" value="free" checked> Free</label>
<label class="hc-radio-label"> <input class="hc-radio" type="radio" name="plan" value="pro"> Pro</label>
<label class="hc-radio-label"> <input class="hc-radio" type="radio" name="plan" value="team"> Team</label>Radios with the same name form a single-select group. Browser-native
arrow-key navigation works automatically; you don’t need to add
role="radiogroup" or any roving-tabindex JS unless you want to group
visually across non-adjacent inputs.
Variants
Section titled “Variants”data-variant accepts success, warning, and error for
non-default fill colors when checked. The default (omitted) variant
uses the active color theme’s primary fill.
Default (themed)
Success
Warning
Error
<!-- Separate `name`s here only so each variant can render as checked. --><input class="hc-radio" type="radio" name="v-default" checked><input class="hc-radio" type="radio" name="v-success" data-variant="success" checked><input class="hc-radio" type="radio" name="v-warning" data-variant="warning" checked><input class="hc-radio" type="radio" name="v-error" data-variant="error" checked>data-size accepts sm, md (default), and lg. Independent of
data-density — dedicated --hc-radio-{sm,lg}-size vars stay
fixed across density tiers.
Small
Default
Large
<input class="hc-radio" type="radio" name="x" data-size="sm" checked><input class="hc-radio" type="radio" name="y" checked><input class="hc-radio" type="radio" name="z" data-size="lg" checked>data-size | Outer dimension |
|---|---|
sm | 0.875rem (14 px) |
md | 1.125rem (18 px) — default |
lg | 1.375rem (22 px) |
States
Section titled “States”Focus me to see the ring
Required field (aria-invalid)
Disabled (unchecked)
Disabled (checked)
<input class="hc-radio" type="radio" name="notify" aria-invalid="true"><!-- A disabled group with one option pre-selected. --><input class="hc-radio" type="radio" name="plan" disabled><input class="hc-radio" type="radio" name="plan" disabled checked>Grouping with hc-field
Section titled “Grouping with hc-field”For form layout, wrap the group in hc-field
to share a label and validation message across radios.
<fieldset class="hc-field"> <legend class="hc-field__label">Notification frequency</legend> <label class="hc-radio-label"> <input class="hc-radio" type="radio" name="freq" value="now" checked> Immediately </label> <label class="hc-radio-label"> <input class="hc-radio" type="radio" name="freq" value="daily"> Daily digest </label> <label class="hc-radio-label"> <input class="hc-radio" type="radio" name="freq" value="weekly"> Weekly digest </label> <p class="hc-field__message">You can change this any time in settings.</p></fieldset><fieldset> + <legend> is the semantic primitive for grouping
related radios; hc-field styles them consistently with other form
patterns.
htmx usage
Section titled “htmx usage”A radio change can drive an htmx request like any other input.
<label class="hc-radio-label"> <input class="hc-radio" type="radio" name="layout" value="grid" data-hx-post="/prefs/layout" data-hx-trigger="change"> Grid</label>Accessibility
Section titled “Accessibility”- The component preserves the native
<input type="radio">, so assistive tech announces it correctly, exposes the group’s position, and arrow keys move focus between members. - Group radios by giving them the same
name. Visually grouping matters too — wrap related radios in a<fieldset>with a<legend>. - For validation errors set
aria-invalid="true"on the relevant inputs. - Prefer the native
disabledattribute when a radio must not be interactive. Usearia-disabled="true"only when it must remain focusable. - Do not remove the focus outline. The component replaces the default
outline with a visible box-shadow ring driven by
--hc-color-focus-ring.
Theming tokens
Section titled “Theming tokens”Component tokens (in component.tokens.json):
| Token path | Purpose |
|---|---|
radio.size | Outer dimension (circle). |
radio.border / border-width | Border in the unchecked state. |
radio.bg | Background in the unchecked state. |
radio.checked-bg / checked-border | Default-variant checked colors. |
radio.success-checked-bg / success-checked-border | data-variant="success". |
radio.warning-checked-bg / warning-checked-border | data-variant="warning". |
radio.error-checked-bg / error-checked-border | data-variant="error". |
radio.sm.size / lg.size | data-size="sm" / "lg" dedicated sizes. |
radio.error-border | Border when aria-invalid="true". |
radio.disabled-bg | Background when disabled. |
radio.label-gap | Gap between the input and its text. |
CSS variables
Section titled “CSS variables”Show the generated CSS variables
--hc-radio-size--hc-radio-border-width | -border--hc-radio-bg--hc-radio-checked-bg | -checked-border--hc-radio-success-checked-bg | -success-checked-border--hc-radio-warning-checked-bg | -warning-checked-border--hc-radio-error-checked-bg | -error-checked-border--hc-radio-sm-size | -lg-size--hc-radio-error-border--hc-radio-disabled-bg--hc-radio-label-gap--hc-color-focus-ring--hc-color-error