registry:ui · Data Entry
toggle — the native checkbox, painted as a switch
Native checkbox painted as a switch: ONE element — the input is the rail (the standard layer's jx-html-switch utility draws the capsule and its ::before knob). Rail geometry rides the density lanes (xs 32×16 · sm 36×18 · default 40×20 · lg 48×24); checked slides the knob by width − track and flips it to primary-foreground over 200ms cubic-bezier; checked = $bindable; the label renders as a sibling label[for].
$npx jixoai-ui add toggle
https://ui.jixoai.com/r/toggle.json
usage
Usage
Use bind:checked for controlled state; a named toggle remains a native checkbox field in forms.
<!-- the label renders as a sibling label[for] above the control; checked is $bindable -->
<Toggle label="notifications" bind:checked />
<!-- density controls the rail through the shared control aliases -->
<Toggle label="compact" density="sm" />
<Toggle label="roomy" density="lg" />toggle
a native checkbox painted as a switch — the label renders as a sibling label[for], and the input IS the rounded rail: the standard layer's jx-html-switch utility draws the capsule and its ::before knob, so keyboard toggling and form participation are the platform's own.
<Toggle
label="notifications"
bind:checked
/>toggle
The switch, painted by the standard layer
One element carries the whole control: the native input IS the rounded rail — the jx-html-switch utility paints the capsule on the element and its ::before knob, so form participation, keyboard toggling, and :checked state stay the platform's own.
The rail geometry rides the density lanes — --jx-toggle-track is var(--jx-line), the width is twice the
track, and the knob is the track minus one unit — measured on this page:
xs 32×16, sm 36×18, default 40×20, lg 48×24. Checked slides the knob by width − track (20px at the default rung)
and flips it to primary-foreground over the primary ring — 200ms
cubic-bezier(0.22, 1, 0.36, 1). The label renders as a sibling label[for] above the control.
<!-- the label renders as a sibling label[for] above the control; checked is $bindable -->
<Toggle label="notifications" bind:checked />
<!-- density controls the rail through the shared control aliases -->
<Toggle label="compact" density="sm" />
<Toggle label="roomy" density="lg" />composition
In a submitted form
The one controlled field shape in the example form: the binding drives UI state live while the underlying checkbox still submits its name/value pair into FormData — checked contributes the value, unchecked contributes nothing.
toggle · in a form
sign up — the FormData payload prints here<script lang="ts">
import PressButton from '@ui/press-button.svelte';
import TerminalCard from '@ui/terminal-card.svelte';
import Toggle from '@ui/toggle.svelte';
</script>
let beta = $state(false);
let result = $state<{ outputs: string[] } | null>(null);
function onSubmit(event: SubmitEvent) {
event.preventDefault();
const data = new FormData(event.currentTarget as HTMLFormElement);
const outputs: string[] = [];
for (const [key, value] of data) {
if (typeof value === 'string' && value !== '') outputs.push(`${key}: ${value}`);
}
outputs.push('form submitted ✓');
result = { outputs };
}
<div class="grid w-full gap-6 min-[900px]:grid-cols-[minmax(0,1fr)_minmax(0,0.9fr)]">
<form class="flex flex-col gap-4" aria-label="beta channel" onsubmit={onSubmit}>
<Toggle label="join the beta channel" name="beta" value="yes" bind:checked={beta} />
<span class="text-muted-foreground text-[12.5px]">
bound checked: <code class="text-accent">{String(beta)}</code> — the value rides into
FormData as <code class="text-accent">beta=yes</code> only when on
</span>
<div class="flex flex-wrap items-center gap-3 pt-1">
<PressButton type="submit" variant="fill">sign up</PressButton>
</div>
</form>
<div>
{#if result}
{#key result}
<TerminalCard
barTitle="form — zsh"
command="form.submit"
outputs={result.outputs}
/>
{/key}
{:else}
<div class="border-border bg-muted/40 text-muted-foreground flex h-full min-h-40 flex-col items-center justify-center gap-2 border p-6 text-center text-[13px]">
<span class="font-nav text-primary text-[11px] uppercase tracking-[0.24em]">awaiting submit</span>
<span>flip the toggle and press <code class="text-accent">sign up</code> — the FormData payload prints here</span>
</div>
{/if}
</div>
</div>types
Toggle variants
Choose a density for rail geometry, then bind checked when state must stay in sync.
toggle · variants
<script lang="ts">
import Toggle from '@ui/toggle.svelte';
</script>
<div class="grid w-full gap-4 sm:grid-cols-3">
<div class="border border-border p-4"><Toggle label="off" name="types-off" /></div>
<div class="border border-border p-4"><Toggle label="on" name="types-on" checked /></div>
<div class="border border-border p-4"><Toggle label="disabled" name="types-disabled" disabled /></div>
</div>a11y
Accessibility
The native input keeps keyboard reachability and paints the focus indication on the visible rail itself.
Keyboard
| Key | Action |
|---|---|
| Space | Toggle the focused switch |
| Tab | Move focus to or past the switch |
ARIA
| Attribute | Value | Description |
|---|---|---|
| role | switch | On the native checkbox input — the switch pattern over native semantics |
| aria-checked | native | State is exposed by the checkbox input |
theming
Density and tokens
The shared density scope controls label rhythm and the proportional rail geometry.
| Token | Default | Source |
|---|---|---|
| --jx-toggle-track | var(--jx-line) | component |
| --jx-toggle-width | calc(var(--jx-toggle-track) * 2) | component |
| --jx-toggle-knob | calc(var(--jx-toggle-track) - var(--jx-unit)) | component |
| --jx-toggle-knob-border | 1px | component |
| --jx-toggle-knob-border-color | var(--primary) | component |
| --jx-hit | 28 / 32 / 40 / 48px | density |
| --jx-gap | 8 / 8 / 12 / 16px | density |
| --jx-text | 11 / 12 / 13 / 15px | 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. §4's frozen exception: the toggle's kernel formulas (--jx-toggle-track/width/knob) are effective-operand compositions and stay EXACTLY as-is — only the axis surface changed.
Toggle · universal props
<!-- the eight-axis surface; the kernel formulas stay frozen (§4) -->
<Toggle label="autopilot" density="small" />
<Toggle label="autopilot" radius="medium" />api
API
Props extend native HTML input attributes; these additions define the toggle contract.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
checked bind | boolean | false | Bindable on/off state. |
| label | string | — | Text rendered before the rail. |
| disabled | boolean | false | Disables interaction and mutes the control. |
| name | string | — | Form field name passed to the native input. |
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) |