Switch
ON/OFF toggle with immediate effect. Material parity (`/components/switch`). Distinct from Checkbox — switch implies "this changes state right now"; checkbox implies "I'm submitting this value with the form."
Spec — Switch
Facet *isual*do Koder Design. Material parity: https://m3.material.io/components/switch.
Anatomy
OFF: ●──── (handle left, track muted)
ON: ────● (handle right, track accent)- *rack* 52×32 px (default), radius-full pill
- *andle (thumb)* 24 px circle, shifts left↔right
- *it zone* 48×48 px
R1 — Switch vs Checkbox
Critical distinction:
| Use Switch when… | Use Checkbox when… |
|---|---|
| Action takes effect IMMEDIATELY | Action is part of a FORM submit |
| Single setting, no form context | Multiple options or terms acceptance |
| User can see the system change (WiFi, mute) | The change applies on Save |
| Quick toggle in toolbar | Per-row selection in a list |
Rule of thumb: if user must click a "Save" button after, use checkbox. If the change persists the moment they toggle, use switch.
R2 — States
| State | Track | Handle |
|---|---|---|
| OFF + enabled | surface-variant bg |
surface circle |
| OFF + hover | text-muted 8% bg |
+ ring outline |
| OFF + focused | + focus ring | + focus ring |
| ON + enabled | accent bg |
accent-on circle |
| ON + hover | accent-strong bg |
+ slight scale |
| ON + focused | + focus ring | + focus ring |
| Disabled | 38% opacity | 38% opacity |
R3 — Optional icons
Switch can show icons inside handle/track:
| Style | Visual |
|---|---|
| *o icons*(default) | Plain pill |
| *andle icon* | Small icon inside handle (24 px) — check/x or feature glyph |
| *rack icons* | Icons at both ends of track (smaller, indicating state semantics) |
Optional; doesn't change behavior. Material 3 default includes check/x in handle for accessibility (visual state cue beyond color).
R4 — Animation
- Handle slides smoothly left↔right on toggle (motion-fast, ~150ms)
- Track color animates simultaneously
- Reduced-motion: instant (no slide)
- Sound (optional, app-specific): subtle click on toggle
R5 — Optimistic state
When toggling has async effect (server save), follow optimistic pattern:
- User toggles → switch UI immediately shifts to new state
- Async call kicks off in background
- If success: stay
- If failure: snap back to previous state + show error snackbar
("Couldn't enable notifications. Try again.")
NEVER show a spinner WITHIN the switch on async — it freezes the visual feedback.
R6 — Settings convention
In Settings pages, switch rows have this canonical layout:
┌────────────────────────────────────────────────────┐
│ [icon?] Title [●──] │
│ Optional description text │
└────────────────────────────────────────────────────┘- Icon (leading, optional)
- Title (
title-medium) - Description (
body-smallmuted) below title - Switch right-aligned (or left in RTL)
- Whole row clickable
KoderSettingsTile.toggle() widget (per future settings/patterns.kmd) — exposed by koder_kit.
R7 — Accessibility
<input type="checkbox" role="switch">(HTML standard, bothattributes)
- OR native Flutter
Switchwidget aria-checked="true"/"false"(set automatically with role=switch)- Visible focus ring
- Keyboard: Space toggles
- Screen reader announces: "Switch, Notifications, on" (or off)
- High-contrast: not just color — handle position is the primary cue
R8 — Forbidden patterns
- ❌ Switch for form submission semantics (use checkbox)
- ❌ Switch without label (always provide accessible name)
- ❌ Switch that requires confirm dialog after toggle (defeats the
"immediate" semantic — use checkbox + button instead)
- ❌ More than ~10 switches in one page (becomes overwhelming;
group into sub-sections)
- ❌ Tri-state switch (use radio group for >2 options)
R9 — Per-preset variation
| Preset | Visual |
|---|---|
material3 |
Pill track + circular handle |
ios_cupertino |
Same shape, slightly larger; uses iOS green for ON |
gnome |
Less rounded pill (radius |
windows_11 |
Mica backdrop track + handle |
brutalist |
Sharp rectangle track + sharp square handle |
terminal_classic |
ASCII [off] / [ON ] text |
Cross-link
components/checkbox.kmd— vs switch decisioninteraction/states.kmd— state visualsthemes/color-roles.kmd— accent track ONthemes/motion.kmd— slide animation