registry:ui · Data Entry
radio — the icon-ladder ring, scaled dot
Pure-CSS radio: appearance-none + 16px circle, :checked border primary + inner 8px dot (scale 0→1 transition), error wiring identical to checkbox.
radio
appearance-none circle with a scaled dot — the native input keeps form participation, keyboard toggling, and same-name arrow-key walking; the glyph is pure CSS.
edge requires the nightly channel
<Radio
label="node"
name="runtime"
bind:group={picked}
/>
<Radio label="bun" name="runtime" bind:group={picked} />
<Radio label="deno" name="runtime" bind:group={picked} />
<!-- picked = 'bun' -->radio
The selector, redrawn in pure CSS
A control where the paint deserved its own drawing code: the component strips appearance off the native input and draws its glyph with a pseudo-element — a scaled dot. Zero icon fonts, zero SVG, zero dependencies; the native input underneath keeps form participation, keyboard toggling, and :checked state.
:checked turns the border primary and pops the dot (14px at the default rung — the 16/18/20/24 ladder) from scale(0) to scale(1) (150ms ease-out). Same-name radios keep
native arrow-key walking — tab into the group and use the arrows.
<!-- same-name radios keep native arrow-key walking -->
<Radio label="node" name="runtime" checked />
<Radio label="bun" name="runtime" />
<Radio label="deno" name="runtime" />
<!-- labelSide="left" flips the label to the inline-start -->
<Radio label="pro" name="plan" labelSide="left" />types
Radio variants
Same-name radios form one native choice set; use label placement and disabled state as needed.
radio · variants
<script lang="ts">
import Radio from '@ui/radio.svelte';
</script>
<div class="grid gap-4 sm:grid-cols-3">
<div class="border border-border p-4"><Radio label="selected" name="types-radio" checked /></div>
<div class="border border-border p-4"><Radio label="label left" name="types-radio-left" labelSide="left" /></div>
<div class="border border-border p-4"><Radio label="disabled" name="types-radio-disabled" disabled /></div>
</div>usage
Usage
Give every option the same name and bind the selected value when the parent needs it.
<!-- same-name radios keep native arrow-key walking -->
<Radio label="node" name="runtime" checked />
<Radio label="bun" name="runtime" />
<Radio label="deno" name="runtime" />
<!-- labelSide="left" flips the label to the inline-start -->
<Radio label="pro" name="plan" labelSide="left" />a11y
Accessibility
Native radio grouping supplies arrow-key walking and form semantics; the component adds explicit validation wiring.
Keyboard
| Key | Action |
|---|---|
| Arrow keys | Move selection within same-name radio group |
| Space | Select the focused radio |
ARIA
| Attribute | Value | Description |
|---|---|---|
| aria-invalid | true | Set when error is present |
| aria-describedby | {id}-error | References the validation message |
theming
Density and tokens
The ring, dot, and label all consume the shared density scale.
| Token | Default | Source |
|---|---|---|
| --jx-hit | 28 / 32 / 40 / 48px | density |
| --jx-icon | 16 / 18 / 20 / 24px | density |
| --jx-gap | 8 / 8 / 12 / 16px | density |
| --jx-text | 11 / 12 / 13 / 15px | density |
| --jx-line | 16 / 18 / 20 / 24px | density |
axes
Universal props
The eight-axis surface (explicit-props): size · shape · radius · density · color · theme · elevation · motion — each axis takes named steps, auto (inherit the ambient context; stamps nothing), an exact number (px · coefficient · dp · hue per axis), or query() for responsive/container-conditional values. The family CONSUMES size and color: the native element never receives them (the §1 native collision rule).
radio · universal props
<Radio label="px number" size={14} density="small" value="a" group={g} />
<Radio label="named steps" size="large" radius="medium" value="b" group={g} />api
API
Props extend native HTML input attributes; these additions define the radio-specific contract.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
| label | string | — | Same-row label rendered with label[for]. |
group bind | string | number | — | Bindable selected value for the radio channel. |
| labelSide | 'left' | 'right' | 'right' | Places the label before or after the control. |
| error | string | — | Adds invalid state and an associated message. |
Universal props
| Property | Type | Default | Description |
|---|---|---|---|
| size | 'small' | 'medium' | 'large' | 'auto' | number | 'auto' · ambient scope | the base scale — root font-size; parts size in em |
| shape | 'round' | 'scoop' | 'bevel' | 'notch' | 'square' | 'squircle' | 'auto' | 'auto' · ambient scope | corner geometry (CSS corner-shape; §14 degrade table) |
| radius | 'small' | 'medium' | 'large' | 'auto' | number | 'auto' · ambient scope | corner size; auto = the concentric broadcast (§3) |
| density | 'small' | 'medium' | 'large' | 'auto' | number | 'auto' · ambient scope | spacing/leading scale over the kernel channels (§4) |
| color | 'primary' | 'secondary' | 'error' | 'warn' | 'success' | 'info' | 'auto' | number | string | 'auto' · ambient scope | the hue axis of the fixed oklch primary system (§5) |
| theme | 'light' | 'dark' | 'system' | 'auto' | 'auto' · ambient scope | light/dark profile; system = the JS-mutable global (§6) |
| elevation | 'level-1' | 'level0' | 'level1' | 'level2' | 'level3' | 'level4' | 'level5' | 'auto' | number | 'auto' · ambient scope | official M3 levels over the surface ladder (§7) |
| motion | 'reduced' | 'subtle' | 'normal' | 'expressive' | 'auto' | number | 'auto' · ambient scope | intensity across the motion kernels (§8) |