Toggle Switch Theme Toggle
A sun in the thumb slot turns into a moon as the switch flips, and the thumb stretches while pressed. The card follows the switch through :has(:state(--checked)), no JavaScript involved.
Reduced Motion
Your system is set to reduce motion, so the animations shown on this page will not play for you.
Dark mode
Easier on the eyes at night.
Code
The following example assumes that you have imported the component and set up the theme.
<div class="theme-toggle">21 collapsed lines
<div class="card"> <div> <strong>Dark mode</strong> <p>Easier on the eyes at night.</p> </div>
<sv-toggle-switch class="theme-switch" aria-label="Dark mode"> <span class="icons" slot="thumb"> <!-- Sun --> <svg class="sun" aria-hidden="true" viewBox="0 0 24 24"> <circle cx="12" cy="12" r="4" /> <path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4" /> </svg>
<!-- Moon --> <svg class="moon" aria-hidden="true" viewBox="0 0 24 24"> <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z" /> </svg> </span> </sv-toggle-switch> </div></div>
<style>102 collapsed lines
.theme-toggle { display: grid; justify-items: center; padding-block: 1em;
.card { display: flex; gap: 1.5em; align-items: center; padding: 1em 1.25em; color: #26262b; background-color: #fff; border: 1px solid #e2e2e8; border-radius: var(--sv-bdr-rad-lg); transition: 500ms ease; transition-property: color, background-color, border-color;
p { margin: 0.15em 0 0; font-size: 0.85em; opacity: 0.7; } }
&:has(.theme-switch:state(--checked)) .card { color: #e7e7ec; background-color: #18181d; border-color: #2e2e36; } }
.theme-switch { --sv-toggle-switch-bg: #e4e4e9; --sv-toggle-switch-active-bg: #3a3a52; --sv-toggle-switch-thumb-bg: #fff; --sv-toggle-switch-active-clr: #fff; --sv-toggle-switch-sz: 1.75em; --sv-toggle-switch-width: 3.6em; --sv-toggle-switch-dur: 450ms; --sv-toggle-switch-ease: cubic-bezier(0.34, 1.3, 0.64, 1);
--stretch-dur: 200ms;
&::part(background) { display: none; }
&::part(thumb) { box-shadow: 0 1px 3px rgb(0 0 0 / 20%); transition: transform var(--sv-toggle-switch-dur) var(--sv-toggle-switch-ease), inline-size var(--stretch-dur) ease; }
/* The thumb stretches toward the center while pressed */ &:active { --sv-toggle-switch-thumb-width: 2.1em; }
.icons { display: grid; place-items: center; block-size: 100%; }
svg { grid-area: 1 / 1; inline-size: 60%; fill: none; stroke: currentcolor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: var(--sv-toggle-switch-dur) cubic-bezier(0.65, 0, 0.35, 1); transition-property: rotate, scale, opacity; }
.sun { --hidden-rotate: 90deg;
color: #f59e0b; }
.moon { --hidden-rotate: -90deg;
color: #6366f1; }
/* Hidden icon */ &:not(:state(--checked)) .moon, &:state(--checked) .sun { opacity: 0; rotate: var(--hidden-rotate); scale: 0.5; }
@media (prefers-reduced-motion: reduce) { --sv-toggle-switch-dur: 0s; --stretch-dur: 0s; } }</style>