Skip to main content

Radio

Info:Controls html svelte astro Success: coverage 68/68

A single-choice input: a styled native radio plus a group that manages roving focus and arrow-key navigation.

Live demo

live · @xoji/astro

Radio

A single-choice group

Horizontal

Every tone

Accents

Statuses

Named hues

Sizes & states

sm

md

lg

invalid

disabled

Radio is a styled native <input type="radio">: the real input drives state and keyboard semantics while a custom indicator paints the selected dot in any of the six semantic tones. RadioGroup wraps a set of radios in a role="radiogroup", lays them out vertically or horizontally, and owns the WAI-ARIA roving-tabindex pattern: the group is a single Tab stop and arrow keys move selection between options, wrapping at the ends.

Each radio carries its own label (via the label attribute or default-slot text), an invalid state, and a disabled state; the group can disable as a whole. State lives on the native input, so form participation and submission come for free.

When to use

How this component composes with the rest of the set.

Wrap radios in a RadioGroup so arrow keys move selection and the set is a single Tab stop.
Pair with Field to attach a shared label, help text, and error to the whole group.
Give every radio in a set the same name so native form submission yields one value.

Props

10 props, straight from the manifest.

PropTypeDefaultBindingsDescription
tone FullTone
accent neutral danger success warn info accent-2 accent-3 accent-4 red orange yellow green blue purple brown pink cyan gray white black
accent
html svelte astro
Semantic color of the checked indicator. Radio only.
size Size
sm md lg
md
html svelte astro
Control size. Radio only.
name string
html svelte astro
The shared form name that groups native radios into one choice. Radio only.
value string on
html svelte astro
The submitted value when this radio is checked. Radio only.
checked boolean false
html svelte astro
Whether this radio is selected. Two-way bindable in Svelte. Radio only.
invalid boolean false
html svelte astro
Marks the radio invalid, danger-colored ring plus `aria-invalid`. Radio only.
label string
html svelte astro
Accessible label text. On a Radio it is the option label; on a RadioGroup it names the whole group.
labelledby string
html svelte astro
ID of an external element labelling the radio or group, when `label` is not used.
orientation "vertical" | "horizontal"
vertical horizontal
vertical
html svelte astro
Layout direction and `aria-orientation` of the group. RadioGroup only.
disabled boolean false
html svelte astro
Disables interaction. On a Radio it disables that option; on a RadioGroup it marks the whole group `aria-disabled`.

Appearance

Variants

accent

.xoji-radio--accent

The checked indicator fills with the accent tone (the default).

neutral

.xoji-radio--neutral

Neutral-toned checked indicator.

danger

.xoji-radio--danger

Danger-toned checked indicator.

success

.xoji-radio--success

Success-toned checked indicator.

warn

.xoji-radio--warn

Warn-toned checked indicator.

info

.xoji-radio--info

Info-toned checked indicator.

horizontal

.xoji-radio-group--horizontal

Lays the group's options in a wrapping row instead of a column.

Sizes

sm

.xoji-radio--sm

Compact.

md

default
.xoji-radio

Default.

lg

.xoji-radio--lg

Large.

States

hover

.xoji-radio:hover .xoji-radio__indicator

Pointer over the radio: the indicator border and fill shift toward the hover tint.

checked

.xoji-radio__control:checked ~ .xoji-radio__indicator

Selected: the indicator fills with the tone color and the dot scales in.

focus-visible

.xoji-radio__control:focus-visible ~ .xoji-radio__indicator

Keyboard focus: a token-colored ring on the indicator plus a transparent outline promoted in forced-colors mode.

invalid

.xoji-radio--invalid .xoji-radio__indicator

Marked invalid: the indicator border turns danger-colored.

disabled

.xoji-radio__control:disabled ~ .xoji-radio__indicator, .xoji-radio[aria-disabled="true"]

Non-interactive: muted fill and ink, no pointer.

Anatomy

The named parts that make up the component, with their selectors.

radio

.xoji-radio

The <label> wrapper for a single option, carrying the tone, size, and invalid classes.

--font-sans --text-body --leading-normal --fg-0 --space-2

control

.xoji-radio__control

The native <input type="radio">, visually hidden but present for state, focus, and form submission.

indicator

.xoji-radio__indicator

The painted circle that fills with the tone color and shows the dot when checked.

--border-normal --field-border --field-bg --radius-full --duration-fast --ease-standard --ease-emphasized

label

.xoji-radio__label

The text content for the option, taken from the label attribute or the default slot.

group

.xoji-radio-group

The role="radiogroup" container plus its optional label, laid out by orientation.

--font-sans --space-2 --space-4 --text-sm --weight-medium --fg-1 --leading-normal

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 68/68 consumed tokens produced default register: 276 tokens

Live coverage check against the xoji-default register (derive(xojiDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--accent --accent-2 --accent-2-fg --accent-3 --accent-3-fg --accent-4 --accent-4-fg --accent-fg --black --black-fg --blue --blue-fg --border-normal --border-thick --brown --brown-fg --cyan --cyan-fg --danger --danger-fg --duration-fast --ease-emphasized --ease-standard --fg-0 --fg-1 --fg-disabled --field-bg --field-border --font-sans --gray --gray-fg --green --green-fg --info --info-fg --leading-normal --line --line-2 --neutral --neutral-fg --orange --orange-fg --pink --pink-fg --purple --purple-fg --radius-full --red --red-fg --ring --space-1 --space-2 --space-3 --space-4 --state-disabled --state-hover --success --success-fg --text-body --text-lg --text-sm --warn --warn-fg --weight-medium --white --white-fg --yellow --yellow-fg

Slots

default
html svelte astro

On a Radio, the option's label text. On a RadioGroup, the radio options.

Accessibility

Each Radio is a native <input type="radio">, so selection, keyboard, and form semantics come for free.
RadioGroup is a role="radiogroup" with aria-orientation; it implements the roving-tabindex pattern: one Tab stop, arrows move selection and wrap.
A radio needs an accessible name from label, default-slot text, labelledby, or aria-label; the binding warns at runtime when none is present.
The group needs a name from label, labelledby, or aria-label; the binding warns when it is missing.
invalid sets aria-invalid on the input alongside the danger-colored ring.
The indicator is decorative (aria-hidden); state is conveyed by the native input's checked state.
Focus shows a token ring on the indicator plus a transparent outline the forced-colors base rule promotes to a real system outline.

Code

Grouped choice and tones

A labelled vertical group with roving focus, plus standalone toned radios.

<xoji-radio-group label="Plan" orientation="vertical">
	<xoji-radio name="plan" value="free" label="Free" checked></xoji-radio>
	<xoji-radio name="plan" value="pro" label="Pro" tone="accent"></xoji-radio>
	<xoji-radio name="plan" value="team" label="Team"></xoji-radio>
</xoji-radio-group>

<xoji-radio name="confirm" value="yes" tone="success">I agree to the terms</xoji-radio>

<xoji-radio name="confirm" value="no" tone="danger" invalid label="Decline"></xoji-radio>
<script lang="ts">
	import { Radio, RadioGroup } from "@xoji/svelte";
	let plan = $state("free");
</script>

<RadioGroup label="Plan" orientation="vertical" onchange={(e) => (plan = (e.target as HTMLInputElement).value)}>
	<Radio name="plan" value="free" label="Free" checked={plan === "free"} />
	<Radio name="plan" value="pro" label="Pro" tone="accent" checked={plan === "pro"} />
	<Radio name="plan" value="team" label="Team" checked={plan === "team"} />
</RadioGroup>

<Radio name="confirm" value="yes" tone="success">I agree to the terms</Radio>
---
import { Radio, RadioGroup } from "@xoji/astro";
---

<RadioGroup label="Plan" orientation="vertical">
	<Radio name="plan" value="free" label="Free" checked />
	<Radio name="plan" value="pro" label="Pro" tone="accent" />
	<Radio name="plan" value="team" label="Team" />
</RadioGroup>

<Radio name="confirm" value="yes" tone="success">I agree to the terms</Radio>