Toggle
Import
Section titled “Import”import { Toggle } from '@delightstack/components';Basic Usage
Section titled “Basic Usage”View code
<Toggle label="Dark Mode" />Examples
Section titled “Examples”Simple Toggle
Section titled “Simple Toggle”View code
<Toggle label="Dark Mode" />With On/Off Labels
Section titled “With On/Off Labels”Dynamic text that changes based on the toggle state.
View code
<Toggle on_label="Notifications On" off_label="Notifications Off" />Label Position
Section titled “Label Position”Place the label before or after the toggle.
View code
<Toggle label="Setting" label_position="start" /><Toggle label="Setting" label_position="end" />Indeterminate (Three-State)
Section titled “Indeterminate (Three-State)”Set indeterminate to add a third, in-between state. checked is then
boolean | null — null parks the thumb at a middle stop — and clicking
cycles false → null → true → false. The track lengthens automatically so
all three stops keep distinct touch targets. Useful for tri-state settings
like allow / inherit / deny.
You can also drag the handle straight to any stop (e.g. null → false
without cycling through true). Each stop has a magnetic pull while
dragging, the track rubber-bands if you pull past its ends, and the handle
springs into place on release. Arrow keys step between stops too.
null — Only flagged comments are held for reviewView code
<script> import { Toggle } from '@delightstack/components';
// In indeterminate mode, checked is boolean | null let moderation = $state(null);</script>
<Toggle indeterminate bind:checked={moderation} label="Comment moderation" />Custom Thumb Icon
Section titled “Custom Thumb Icon”Use the thumb_icon snippet to render an icon inside the thumb.
View code
<script> import { Toggle } from '@delightstack/components';
let sound = $state(true);</script>
<Toggle bind:checked={sound} label={sound ? 'Sound On' : 'Sound Off'}> {#snippet thumb_icon()} {#if sound} <!-- Volume icon (inline SVG) --> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M19.07 4.93a10 10 0 0 1 0 14.14"></path><path d="M15.54 8.46a5 5 0 0 1 0 7.07"></path></svg> {:else} <!-- Mute icon (inline SVG) --> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><line x1="23" y1="9" x2="17" y2="15"></line><line x1="17" y1="9" x2="23" y2="15"></line></svg> {/if} {/snippet}</Toggle>Form Integration
Section titled “Form Integration”Use name and value for native form submission.
View code
<Toggle name="premium" value="true" label="Enable premium features" />Disabled
Section titled “Disabled”View code
<Toggle label="Disabled off" disabled /><Toggle label="Disabled on" disabled checked />View code
<Toggle size="0" label="Small (32x18)" /><Toggle size="1" label="Default (44x24)" /><Toggle size="2" label="Medium (52x28)" /><Toggle size="3" label="Large (68x36)" />Settings List
Section titled “Settings List”View code
<script> import { Toggle } from '@delightstack/components';
let settings = $state({ notifications: true, autoSave: true, sounds: false, });</script>
<div style="display: flex; flex-direction: column; gap: 1rem;"> <Toggle bind:checked={settings.notifications} label="Push Notifications" name="notifications" value="enabled" /> <Toggle bind:checked={settings.autoSave} label="Auto-save" name="autosave" value="enabled" /> <Toggle bind:checked={settings.sounds} label="Sound Effects" name="sounds" value="enabled" /></div>| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean (or boolean | null with indeterminate) | - | Toggle state, bindable. null is the in-between state (three-state mode only). When omitted inside a Form with a name, the state is context-driven (reads/writes the form data — no bind:checked needed) |
indeterminate | boolean | false | Enable the third, in-between state (checked: null); clicking cycles false → null → true |
disabled | boolean | false | Disable toggle |
size | '0' | '1' | '2' | '3' | '1' | Toggle size |
label | string | - | Label text |
label_position | 'start' | 'end' | 'end' | Label placement relative to toggle |
on_label | string | - | Label text when on |
off_label | string | - | Label text when off |
name | string | - | Form field name. Inside a Form, registers the field and enables context-driven state |
tristate | boolean | false | Three-state mode for tri-state form fields (same track as indeterminate): null/undefined mean “unanswered” (the middle stop), and the user can cycle back to it |
default_checked | boolean | - | Default shown when the form data has no value yet (set by defaulted boolean form fields) |
error | string | - | Error message shown below the toggle (errors from a parent Form context display automatically) |
parse | (value: unknown) => unknown | - | Validator that throws a user-showable message; inside a Form it is registered with the form |
value | string | - | Form value when checked |
tooltip | string | - | Tooltip text on hover |
dense | boolean | false | Tighter label spacing |
comfortable | boolean | false | More label spacing |
id | string | auto | Element ID |
class | string | '' | Additional CSS classes |
thumb_icon | Snippet | - | Custom icon rendered inside the thumb |
Events
Section titled “Events”| Event | Detail | Description |
|---|---|---|
onchange | { checked: boolean } (or boolean | null with indeterminate) | State changed |
Accessibility
Section titled “Accessibility”- Hidden native
<input type="checkbox">for form submission and semantics (itsindeterminateproperty is set whilecheckedisnull) role="switch"on the custom element —role="checkbox"in indeterminate mode, since the switch role has no mixed statearia-checkedreflects toggle state ("mixed"whilecheckedisnull)- Full keyboard support: Space and Enter to toggle (cycles all three states in indeterminate mode); Arrow Left/Right step directly between stops
- The thumb is draggable with pointer or touch, with magnetic snap points and spring physics
- Focus ring visible on keyboard focus (
:focus-visible) - Label associated via
<label>element - Thumb slides with a spring-physics bounce animation (
cubic-bezier(0.34, 1.4, 0.64, 1)) - Press state widens the thumb for tactile feedback