jixoai-ui
the terminal design language
loading the style sheet…
Skip to content
docs · print medium: screen

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].

install — toggle

$npx jixoai-ui add toggle

https://ui.jixoai.com/r/toggle.json

one element — the input is the rail knob slide · 200ms xs → lg rail rungs checked is $bindable label[for] + aria wiring

usage

Usage

Use bind:checked for controlled state; a named toggle remains a native checkbox field in forms.

Toggle usage
<!-- 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-usage.svelte svelte
<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.

checked: true
Toggle usage
<!-- 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

bound checked: false — the value rides into FormData as beta=yes only when on
awaiting submit flip the toggle and press sign up — the FormData payload prints here
toggle-form-demo.svelte svelte
<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

toggle-types-demo.svelte svelte
<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

KeyAction
SpaceToggle the focused switch
TabMove focus to or past the switch

ARIA

AttributeValueDescription
roleswitchOn the native checkbox input — the switch pattern over native semantics
aria-checkednativeState is exposed by the checkbox input

theming

Density and tokens

The shared density scope controls label rhythm and the proportional rail geometry.

xs
sm
default
lg
TokenDefaultSource
--jx-toggle-trackvar(--jx-line)component
--jx-toggle-widthcalc(var(--jx-toggle-track) * 2)component
--jx-toggle-knobcalc(var(--jx-toggle-track) - var(--jx-unit))component
--jx-toggle-knob-border1pxcomponent
--jx-toggle-knob-border-colorvar(--primary)component
--jx-hit28 / 32 / 40 / 48pxdensity
--jx-gap8 / 8 / 12 / 16pxdensity
--jx-text11 / 12 / 13 / 15pxdensity

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

toggle-universal.svelte svelte
<!-- 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

PropertyTypeDefaultDescription
checked bindbooleanfalseBindable on/off state.
label string—Text rendered before the rail.
disabled booleanfalseDisables interaction and mutes the control.
name string—Form field name passed to the native input.

Universal props

PropertyTypeDefaultDescription
size'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopethe base scale — root font-size; parts size in em
shape'round' | 'scoop' | 'bevel' | 'notch' | 'square' | 'squircle' | 'auto''auto' · ambient scopecorner geometry (CSS corner-shape; §14 degrade table)
radius'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopecorner size; auto = the concentric broadcast (§3)
density'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopespacing/leading scale over the kernel channels (§4)
color'primary' | 'secondary' | 'error' | 'warn' | 'success' | 'info' | 'auto' | number | string'auto' · ambient scopethe hue axis of the fixed oklch primary system (§5)
theme'light' | 'dark' | 'system' | 'auto''auto' · ambient scopelight/dark profile; system = the JS-mutable global (§6)
elevation'level-1' | 'level0' | 'level1' | 'level2' | 'level3' | 'level4' | 'level5' | 'auto' | number'auto' · ambient scopeofficial M3 levels over the surface ladder (§7)
motion'reduced' | 'subtle' | 'normal' | 'expressive' | 'auto' | number'auto' · ambient scopeintensity across the motion kernels (§8)
jixoai-ui ui.jixoai.com the jixoai design language

Theme

Brand hue

0°

Auto cycle · 24h