Toggle Switch Examples
The examples below assume that you have imported the component and set up the theme.
Basic
The switch toggles on click, Enter, or Space. It is form-associated, so a label with for targets it like any input.
<div class="switch-basic"> <label for="wifi-switch">Wi-Fi</label> <sv-toggle-switch id="wifi-switch"></sv-toggle-switch></div>
<style> .switch-basic { display: flex; gap: 4em; align-items: center; justify-content: center; padding-block: 1em;
label { cursor: pointer; } }</style>Checked and Disabled
checked turns the switch on from markup, and disabled blocks interaction in either state.
<div class="switch-states"> <div class="row"> <label for="switch-checked">Normal</label> <sv-toggle-switch id="switch-checked" checked></sv-toggle-switch> </div>
<div class="row"> <label for="switch-disabled">Disabled</label> <sv-toggle-switch id="switch-disabled" disabled></sv-toggle-switch> </div>
<div class="row"> <label for="switch-both">Disabled checked</label> <sv-toggle-switch id="switch-both" checked disabled></sv-toggle-switch> </div></div>
<style> .switch-states { display: grid; gap: 0.75em; max-inline-size: 16rem; padding-block: 1em; margin-inline: auto;
.row { display: flex; gap: 0.5em; align-items: center;
label { flex: 1; cursor: pointer; } } }</style>Icons
The checked-icon and unchecked-icon slots replace the built-in check and circle with any markup. A blank background slot removes the icons entirely, and the thumb slot fills the thumb itself, here with a pair of crossfading icons.
<div class="switch-icons"> <div class="row"> <label for="switch-text-icons">Text icons</label> <sv-toggle-switch id="switch-text-icons" class="text-icons" checked> <strong aria-hidden="true" slot="checked-icon">On</strong> <span aria-hidden="true" slot="unchecked-icon">Off</span> </sv-toggle-switch> </div>
<div class="row"> <label for="switch-no-icons">No icons</label> <sv-toggle-switch id="switch-no-icons"> <span slot="background"></span> </sv-toggle-switch> </div>
<div class="row"> <label for="switch-thumb-icon">Icon in the thumb</label> <sv-toggle-switch id="switch-thumb-icon" class="thumb-icons"> <span slot="background"></span>
<div class="custom-thumb" aria-hidden="true" slot="thumb"> <svg class="unchecked" viewBox="0 -960 960 960"> <path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z" /> </svg>
<svg class="checked" viewBox="0 -960 960 960"> <path d="M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z" /> </svg> </div> </sv-toggle-switch> </div></div>
<style> .switch-icons { display: grid; gap: 0.75em; max-inline-size: 16rem; padding-block: 1em; margin-inline: auto;
.row { display: flex; gap: 0.5em; align-items: center;
label { flex: 1; cursor: pointer; } }
.text-icons { [slot="checked-icon"], [slot="unchecked-icon"] { font-size: 0.8em; } }
.thumb-icons { .custom-thumb { display: grid; place-items: center; inline-size: 100%; block-size: 100%;
svg { grid-area: 1 / 1; inline-size: 1.1em; block-size: 1.1em; transition: opacity var(--sv-toggle-switch-dur, 350ms) var(--sv-toggle-switch-ease, cubic-bezier(0.486, 1.45, 0.2, 1)), scale var(--sv-toggle-switch-dur, 350ms) var(--sv-toggle-switch-ease, cubic-bezier(0.486, 1.45, 0.2, 1)); }
.checked { opacity: 0; fill: var(--sv-accent); scale: 0; }
.unchecked { opacity: 1; fill: var(--sv-gray-5); scale: 1; } }
&:state(--checked) .custom-thumb { .checked { opacity: 1; scale: 1; }
.unchecked { opacity: 0; scale: 0; } } } }</style>Styling
--sv-toggle-switch-sz scales the whole switch, the color tokens tint it, and the thumb and track widths can be set apart for other proportions.
<div class="switch-styling"> <div class="variant"> <sv-toggle-switch class="large" aria-label="Large switch" checked></sv-toggle-switch> <span>--sv-toggle-switch-sz</span> </div>
<div class="variant"> <sv-toggle-switch class="tinted" aria-label="Green switch" checked></sv-toggle-switch> <span>--sv-toggle-switch-active-bg</span> </div>
<div class="variant"> <sv-toggle-switch class="slim" aria-label="Slim switch"></sv-toggle-switch> <span>thumb and track widths</span> </div></div>
<style> .switch-styling { display: grid; gap: 1.5em; justify-items: center; padding-block: 1em;
.variant { display: grid; gap: 0.4em; justify-items: center;
span { font-size: 0.8em; color: var(--sv-gray-3); } }
.large { --sv-toggle-switch-sz: 2.2em; }
.tinted { --sv-toggle-switch-active-bg: #22c55e; }
.slim { --sv-toggle-switch-thumb-width: 1.2em; --sv-toggle-switch-thumb-height: 1.2em; --sv-toggle-switch-width: 3.2em; } }</style>Animation
--sv-toggle-switch-dur and --sv-toggle-switch-ease reshape the thumb travel, the icon swap, and the color fade together. The default easing is springy; a zero duration makes the switch instant. The reduced motion fallback wins over both.
Your system is set to reduce motion, so this animation will not play for you.
<div class="switch-animation"> <div class="variant"> <sv-toggle-switch class="slow" aria-label="Slow switch"></sv-toggle-switch> <span>--sv-toggle-switch-dur: 800ms</span> </div>
<div class="variant"> <sv-toggle-switch class="smooth" aria-label="Smooth switch"></sv-toggle-switch> <span>--sv-toggle-switch-ease: ease</span> </div>
<div class="variant"> <sv-toggle-switch class="instant" aria-label="Instant switch"></sv-toggle-switch> <span>--sv-toggle-switch-dur: 0s</span> </div></div>
<style> .switch-animation { display: grid; gap: 1.5em; justify-items: center; padding-block: 1em;
.variant { display: grid; gap: 0.4em; justify-items: center;
span { font-size: 0.8em; color: var(--sv-gray-3); } }
.slow { --sv-toggle-switch-dur: 800ms; }
.smooth { --sv-toggle-switch-ease: ease; }
.instant { --sv-toggle-switch-dur: 0s; } }</style>