Skip to main content

Switch

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

An on/off toggle that applies immediately, with an accessible name and optional state labels.

Live demo

live · @xoji/astro

Switch

A settings panel

Email notifications

Get a digest when something changes.

Email notifications

Reduced motion

Honor system animation preferences.

Reduced motionOff

Beta channel

Locked while a build is in flight.

Beta channel

States & sizes

Off

off

On

on

With labelsYes

labelled

Small

sm

Disabled

disabled

Shape, orientation, direction & label

Vertical follows a wall switch (down off, up on); reverse flips the on/off direction; labelSide moves the label without touching behavior.

Square

square

Vertical

vertical (up = on)

Reversed

reverse (on at left)

Vertical reversed

vertical + reverse

Label after

labelSide=end

Every tone

Toggle all

Toggle any switch: the track lights up while the knob stays a darkened cast of the tone, so it reads in both states. “Toggle all” flips the lot.

Accents

accent accent-2 accent-3 accent-4 neutral

Statuses

success info warn danger

Named hues

red orange yellow green blue purple brown pink cyan gray white black

Switch is a role="switch" toggle for a setting that takes effect immediately, distinct from a checkbox that stages a value until a form submit. It renders a native <button> track with a sliding thumb, so pointer, Space, and Enter all flip it and the state lives in aria-checked.

An optional leading label and optional on-label/off-label state text make the toggle self-describing, and it is form-associated: give it a name (and optional value) and it contributes to form data only while on. Two sizes: the default md and a compact sm.

When to use

How this component composes with the rest of the set.

Pair with Field or a form to capture the toggle; give it a name so it contributes to submitted data.
Use label for a persistent name, or on-label/off-label for a control whose name is its current state.
For a staged value that only applies on submit, reach for a checkbox instead. A switch applies immediately.

Props

14 props, straight from the manifest.

PropTypeDefaultBindingsDescription
checked boolean false
html svelte astro
The on/off state. Two-way bindable in Svelte; reflected to `aria-checked` and the element's `.checked`.
disabled boolean false
html svelte astro
Disables interaction; mutes the track, suppresses the overlay, and sets `aria-disabled`.
size Size
sm md
md
html svelte astro
Control size. Only `sm` differs from the default.
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
Color of the on-state track and thumb ink. Any of the semantic roles, accent variants, or named hues.
shape "pill" | "square"
pill square
pill
html svelte astro
Track and thumb corner shape: the default rounded pill, or a squared track for a chunkier control.
orientation "horizontal" | "vertical"
horizontal vertical
horizontal
html svelte astro
Track axis. Horizontal slides the thumb left-to-right (on at the right); vertical stands the track up and follows a wall switch — down is off, up is on.
reverse boolean false
html svelte astro
Flip the on/off direction: horizontal puts on at the left, vertical puts on at the bottom. The label is unaffected.
labelSide "start" | "end"
start end
start
html svelte astro
Which side the label sits on relative to the track. `end` puts the control first and the label after it.
label string
html svelte astro
Visible leading label, also wired as the accessible name via `aria-labelledby`.
labelledby string
html svelte astro
ID of an external element that names the toggle. Takes precedence over `label`.
onLabel string
html svelte astro
State text shown (and announced as the name, absent `label`) when on.
offLabel string
html svelte astro
State text shown (and announced as the name, absent `label`) when off.
name string
html svelte astro
Form field name; the toggle contributes `value` to form data only while on.
value string on
html svelte astro
The value submitted with the form when the toggle is on.

Appearance

Variants

square

.xoji-switch--square

Squared track and thumb corners.

vertical

.xoji-switch--vertical

Track stood on its end; down is off, up is on.

reverse

.xoji-switch--reverse

On/off direction flipped (on at the left, or the bottom when vertical).

label-end

.xoji-switch--label-end

Label after the control instead of before it.

Sizes

sm

.xoji-switch--sm

Compact.

md

default
.xoji-switch

Default.

States

on

.xoji-switch__track[aria-checked="true"]

Toggle is on: the track fills with the chosen tone (accent by default) and the thumb slides to the end.

hover

.xoji-switch__track:hover::after

Pointer over the track: overlay paints the hover tint.

active

.xoji-switch__track:active::after

Track pressed: overlay paints the press tint.

focus-visible

.xoji-switch__track:focus-visible

Keyboard focus: a token-colored ring, plus a transparent outline that becomes real in forced-colors mode.

disabled

.xoji-switch__track:disabled, .xoji-switch__track[aria-disabled="true"]

Non-interactive: muted track and thumb, overlay suppressed.

Anatomy

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

switch

.xoji-switch

The row wrapper carrying the size and disabled classes and laying out label, track, and state text.

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

track

.xoji-switch__track

The interactive role="switch" button: the pill the thumb slides within.

--space-7 --space-5 --space-2 --border-thin --line-2 --radius-full --neutral-bg --duration-base --ease-emphasized --duration-fast --ease-standard

thumb

.xoji-switch__thumb

The circular knob: a darkened cast of the track's tone, kept visible on and off.

--space-1 --radius-full --elevation-1

label

.xoji-switch__label

The visible leading label that names the toggle and is referenced as its accessible name.

state

.xoji-switch__state

Optional trailing on/off state text; becomes the accessible name when no other label is given.

--fg-2 --text-sm

overlay

.xoji-switch__track::after

The pseudo-element behind the track that paints hover and active state tints.

--state-hover --state-press

Tokens & coverage

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

Success:fully covered 71/71 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 --border-thin --brown --brown-fg --cyan --cyan-fg --danger --danger-fg --duration-base --duration-fast --ease-emphasized --ease-standard --elevation-1 --fg-0 --fg-2 --fg-disabled --font-sans --gray --gray-fg --green --green-fg --info --info-fg --leading-tight --line-2 --neutral --neutral-bg --neutral-fg --orange --orange-fg --pink --pink-fg --purple --purple-fg --radius-full --radius-sm --red --red-fg --ring --space-1 --space-2 --space-4 --space-5 --space-6 --space-7 --state-disabled --state-hover --state-press --success --success-fg --text-body --text-sm --warn --warn-fg --white --white-fg --yellow --yellow-fg

Accessibility

Renders a native <button> with role="switch", so click, Space, and Enter all toggle it; Space's default scroll is prevented.
State is carried in aria-checked and mirrored on the element's reflected .checked, never by color alone.
Requires an accessible name: labelledby wins, then label, then the on/off state text; the binding warns at runtime when none is present.
The thumb and state-only labels are wired so the toggle is always announced with a name, even when only on-label/off-label are given.
Focus is shown with a token ring and a transparent outline that the forced-colors base rule promotes to a real system outline.
disabled blocks interaction and sets aria-disabled; the track is muted and the overlay suppressed.

Code

Labels, tones, shapes, and form association

A named toggle, on/off state text, the compact size, a toned switch, the square / vertical / reversed variants, a form-bound switch, and a disabled one.

<xoji-switch label="Wi-Fi" checked></xoji-switch>

<xoji-switch label="Notifications" on-label="On" off-label="Off"></xoji-switch>

<xoji-switch size="sm" label="Compact mode"></xoji-switch>

<xoji-switch label="Alerts" tone="danger" checked></xoji-switch>

<xoji-switch label="Square" shape="square" checked></xoji-switch>

<xoji-switch label="Vertical" orientation="vertical" checked></xoji-switch>

<xoji-switch label="Reversed" reverse checked></xoji-switch>

<xoji-switch label="Label after" label-side="end" checked></xoji-switch>

<xoji-switch label="Sync" name="sync" value="enabled" checked></xoji-switch>

<xoji-switch label="Locked" disabled checked></xoji-switch>
<script lang="ts">
	import { Switch } from "@xoji/svelte";

	let wifi = $state(true);
	let notify = $state(false);
</script>

<Switch label="Wi-Fi" bind:checked={wifi} />

<Switch label="Notifications" onLabel="On" offLabel="Off" bind:checked={notify} />

<Switch size="sm" label="Compact mode" />

<Switch label="Alerts" tone="danger" checked />

<Switch label="Square" shape="square" checked />

<Switch label="Vertical" orientation="vertical" checked />

<Switch label="Reversed" reverse checked />

<Switch label="Label after" labelSide="end" checked />

<Switch label="Sync" name="sync" value="enabled" bind:checked={wifi} />

<Switch label="Locked" disabled checked />
---
import { Switch } from "@xoji/astro";
---

<Switch label="Wi-Fi" checked />

<Switch label="Notifications" onLabel="On" offLabel="Off" />

<Switch size="sm" label="Compact mode" />

<Switch label="Alerts" tone="danger" checked />

<Switch label="Square" shape="square" checked />

<Switch label="Vertical" orientation="vertical" checked />

<Switch label="Reversed" reverse checked />

<Switch label="Label after" labelSide="end" checked />

<Switch label="Sync" name="sync" value="enabled" checked />

<Switch label="Locked" disabled checked />