Component
Stablev1.0.0Form

Toggle / Switch

Toggle switches allow users to turn a single setting on or off immediately. Unlike Checkbox which requires form submission, Toggle fires the action instantly on change.

When to Use

Use Toggle when
  • Turning a feature on or off immediately (no save button)
  • Settings pages — notifications, preferences, feature flags
  • Binary state that takes effect instantly
Don't use Toggle when
  • Selection in a form that requires submit — use Checkbox
  • Choosing one option from multiple — use Radio Group
  • Action needs confirmation before firing

Anatomy

1
Track
The pill-shaped background. Off: bg:#E2E8F0. On: bg:#6366F1. Width:44px, height:24px, border-radius:999px. Transition: background 0.2s ease.
2
Thumb
White circle that slides inside the track. 20px diameter. Translates 0 → 20px when toggled. box-shadow for elevation. Transition: transform 0.2s cubic-bezier(0.4,0,0.2,1).
3
Label (optional)
Text to the right of the toggle. 13px fw-500. Describes the setting being toggled. Always present for accessibility.
4
Native input
Hidden input[type=checkbox] underneath — retains all native accessibility, keyboard support, and form behavior.

Variants

Off (default)
On
With sub-label
Disabled

States

Off
bg:#E2E8F0, thumb left
On
bg:#6366F1, thumb right
Disabled On
opacity:.45, cursor:not-allowed
Disabled Off
opacity:.45, no interaction

Properties

PropertyTypeRequiredDefaultDescription
checkedbooleanoptionalfalseControlled on/off state.
onChangefunctionrequiredCalled immediately on toggle. Fires before any save action. (e: ChangeEvent) => void
disabledbooleanoptionalfalsePrevents interaction. opacity:.45, cursor:not-allowed.
labelstringrequiredVisible label. Also used as aria-label for screen readers.
subLabelstringoptionalundefinedSecondary description below label.

Behavior

TriggerBehavior
Click / tapInstantly fires onChange with new value. Track background transitions (0.2s). Thumb translates (0.2s cubic-bezier). No confirmation needed.
Space keyToggles when focused. Native checkbox behavior.
DisabledNo toggle, no hover, no animation. opacity:.45.
LoadingWhen saving in progress: disable toggle + show spinner in place of thumb. Re-enable after save completes.

Accessibility

RequirementImplementation
RoleUse native input[type=checkbox] underneath — inherits role="switch" automatically in modern browsers, or add role="switch" explicitly.
aria-checked"true" when on, "false" when off. Native checkbox handles this.
LabelAlways wrap in <label> or use aria-labelledby pointing to visible label text.
KeyboardTab focuses, Space toggles. All native.
Touch targetTrack is 44×24px — minimum. Wrap in <label> to extend hit area to include label text.

Composition

Allowed
Settings page — list of toggles per category
Inside cards with label + sub-label
Inline in table rows (feature flags)
Forbidden
Inside forms that require Submit button
For choosing between multiple options (use Radio)
Without a visible label

Best Practices

Do
Clear label + sub-label. Immediate action understood.
Don't
No label — screen readers can't announce purpose.

Content Rules

Email notifications
Noun phrase. What is being toggled.
Enable email notifications when you receive a new message
Too verbose. Labels max 4 words.
Receive alerts about new activity
Explains what the setting does.
Toggle this to turn on or turn off
Describes the UI, not the feature.

AI Implementation Guide

For AI coding assistants: Toggle is built on a hidden input[type=checkbox] with a custom CSS track+thumb overlay. Always wrap in <label> for click area. Track: 44×24px pill, bg:#E2E8F0 (off) → bg:#6366F1 (on). Thumb: 20px white circle, translateX(0) → translateX(20px). Both transitions use 0.2s. Never use Toggle inside a form that has a Save button — use Checkbox instead. Toggle fires onChange immediately.

Design Decisions

Why custom CSS instead of input[type=checkbox] with appearance:none?
The hidden native checkbox approach retains all accessibility benefits (keyboard, screen reader, form submit) while allowing full visual customization via the CSS overlay. appearance:none on the input itself has inconsistent cross-browser behavior for the toggle shape.
Why #6366F1 (indigo) for the on state?
Consistent with the primary accent color system. The on state signals "active/enabled" and indigo is the primary interactive color across buttons, focus rings, and active states in the design system.

Changelog

v1.0.0July 2026Added
  • Initial release — on/off, disabled states
  • Built on hidden native checkbox for full accessibility
  • 0.2s thumb slide + track color transition