Skip to content

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.

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.

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.

data-size accepts sm, md (default), and lg. Independent of data-density — dedicated --hc-radio-{sm,lg}-size vars stay fixed across density tiers.

data-sizeOuter dimension
sm0.875rem (14 px)
md1.125rem (18 px) — default
lg1.375rem (22 px)

For form layout, wrap the group in hc-field to share a label and validation message across radios.

Notification frequency

You can change this any time in settings.

<fieldset> + <legend> is the semantic primitive for grouping related radios; hc-field styles them consistently with other form patterns.

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>
  • 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 disabled attribute when a radio must not be interactive. Use aria-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.

Component tokens (in component.tokens.json):

Token pathPurpose
radio.sizeOuter dimension (circle).
radio.border / border-widthBorder in the unchecked state.
radio.bgBackground in the unchecked state.
radio.checked-bg / checked-borderDefault-variant checked colors.
radio.success-checked-bg / success-checked-borderdata-variant="success".
radio.warning-checked-bg / warning-checked-borderdata-variant="warning".
radio.error-checked-bg / error-checked-borderdata-variant="error".
radio.sm.size / lg.sizedata-size="sm" / "lg" dedicated sizes.
radio.error-borderBorder when aria-invalid="true".
radio.disabled-bgBackground when disabled.
radio.label-gapGap between the input and its text.
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
  • Checkbox — multi-select sibling.
  • Field — wraps a control with a label and message.