Open demo

CSS code

HTML
<div><span class="lbl">Sun to moon</span><div class="row">
<label class="dn"><input type="checkbox" role="switch" aria-label="Dark mode"><i><em></em><em></em><em></em></i></label>
<label class="dn"><input type="checkbox" role="switch" aria-label="Dark mode" checked><i><em></em><em></em><em></em></i></label></div></div>
<div><span class="lbl">Icon pair for a header</span><div class="row">
<label class="ic"><input type="checkbox" role="switch" aria-label="Dark mode"><em></em><b aria-hidden="true">☀</b><b aria-hidden="true">☾</b></label>
<label class="ic"><input type="checkbox" role="switch" aria-label="Dark mode" checked><em></em><b aria-hidden="true">☀</b><b aria-hidden="true">☾</b></label></div></div>
CSS
/* Day / night switches: a visually hidden checkbox (checked = dark) followed by the drawn control. */
.dn input,.ic input{position:absolute;opacity:0;width:0;height:0;margin:0}
.dn{position:relative;display:inline-block;width:76px;height:36px;cursor:pointer}
.dn i{position:absolute;inset:0;border-radius:999px;background:linear-gradient(#0284c7,#0369a1);
  transition:background .3s;overflow:hidden}
.dn i::before{content:"";position:absolute;top:4px;left:4px;width:28px;height:28px;border-radius:50%;
  background:#fde68a;box-shadow:0 0 0 3px rgba(253,230,138,.45);transition:transform .3s,background .3s,box-shadow .3s}
.dn input:checked+i{background:linear-gradient(#1e293b,#0f172a)}
.dn input:checked+i::before{transform:translateX(40px);background:#e2e8f0;
  box-shadow:inset -7px -3px 0 0 #94a3b8}
.dn i em{position:absolute;width:3px;height:3px;background:#fff;border-radius:50%;opacity:0;transition:opacity .3s}
.dn i em:nth-child(1){top:8px;left:12px}.dn i em:nth-child(2){top:20px;left:22px}
.dn i em:nth-child(3){top:12px;left:30px}
.dn input:checked+i em{opacity:.85}
.dn input:focus-visible+i{outline:2px solid #2563eb;outline-offset:3px}
/* icon pair for a header */
.ic{display:inline-flex;align-items:center;gap:8px;cursor:pointer;background:#e2e8f0;
  border-radius:999px;padding:5px;position:relative}
.ic em{position:absolute;top:5px;left:5px;width:32px;height:32px;background:#fff;border-radius:50%;
  box-shadow:0 1px 3px rgba(15,23,42,.2);transition:transform .22s}
.ic b{position:relative;z-index:2;width:32px;height:32px;display:grid;place-items:center;font-size:1rem}
.ic input:checked~em{transform:translateX(40px)}
.ic input:focus-visible~em{outline:2px solid #2563eb;outline-offset:2px}
@media (prefers-reduced-motion:reduce){.dn i,.dn i::before,.dn i em,.ic em{transition:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Sun to moon</span><div class="demo-row">
<div class="form-check form-switch dn"><input class="form-check-input" type="checkbox" role="switch" aria-label="Dark mode"></div>
<div class="form-check form-switch dn"><input class="form-check-input" type="checkbox" role="switch" aria-label="Dark mode" checked></div></div></div>
<div><span class="lbl">Icon pair for a header</span><div class="demo-row">
<label class="ic position-relative d-inline-flex align-items-center gap-2 rounded-pill bg-body-secondary"><input class="visually-hidden" type="checkbox" role="switch" aria-label="Dark mode"><em class="rounded-circle"></em><b aria-hidden="true">☀</b><b aria-hidden="true">☾</b></label>
<label class="ic position-relative d-inline-flex align-items-center gap-2 rounded-pill bg-body-secondary"><input class="visually-hidden" type="checkbox" role="switch" aria-label="Dark mode" checked><em class="rounded-circle"></em><b aria-hidden="true">☀</b><b aria-hidden="true">☾</b></label></div></div>
CSS
/* Sun to moon: a Bootstrap .form-switch whose background is three layers — knob, stars, sky. Checked = dark. */
.dn{--dn-sun:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-18 -18 36 36'><circle r='17' fill='%23fde68a' fill-opacity='.45'/><circle r='14' fill='%23fde68a'/></svg>");
  --dn-moon:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-18 -18 36 36'><clipPath id='c'><circle r='14'/></clipPath><circle r='14' fill='%2394a3b8'/><circle cx='-7' cy='-3' r='14' fill='%23e2e8f0' clip-path='url(%23c)'/></svg>");
  --dn-stars:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 76 36'><g fill='%23fff' fill-opacity='.85'><circle cx='13.5' cy='9.5' r='1.5'/><circle cx='23.5' cy='21.5' r='1.5'/><circle cx='31.5' cy='13.5' r='1.5'/></g></svg>");
  display:inline-block;min-height:0;margin:0;padding:0;line-height:0}
.dn .form-check-input{width:76px;height:36px;margin:0;float:none;border:0;border-radius:999px;cursor:pointer;
  background-color:#0369a1;background-image:var(--dn-sun),linear-gradient(transparent,transparent),linear-gradient(#0284c7,#0369a1);
  background-size:contain,100% 100%,100% 100%;background-position:left center,0 0,0 0;transition:background-position .3s}
.dn .form-check-input:checked{background-color:#0f172a;
  background-image:var(--dn-moon),var(--dn-stars),linear-gradient(#1e293b,#0f172a);background-position:right center,0 0,0 0}
.dn .form-check-input:focus{box-shadow:none}
.dn .form-check-input:focus-visible{outline:2px solid #2563eb;outline-offset:3px}
/* icon pair for a header: visually hidden checkbox + sliding disc */
.ic{--bs-secondary-bg-rgb:226,232,240;padding:5px;cursor:pointer}
.ic em{position:absolute;top:5px;left:5px;width:32px;height:32px;background:#fff;
  box-shadow:0 1px 3px rgba(15,23,42,.2);transition:transform .22s}
.ic b{position:relative;z-index:2;width:32px;height:32px;display:grid;place-items:center;font-size:1rem}
.ic input:checked~em{transform:translateX(40px)}
.ic input:focus-visible~em{outline:2px solid #2563eb;outline-offset:2px}
@media (prefers-reduced-motion:reduce){.dn .form-check-input,.ic em{transition:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#64748b] uppercase">Sun to moon</span><div class="flex flex-wrap items-center gap-[18px]">
<label class="relative inline-block h-9 w-[76px] cursor-pointer"><input type="checkbox" role="switch" aria-label="Dark mode" class="peer sr-only"><span class="absolute inset-0 rounded-full bg-linear-to-b from-sky-top to-sky-bottom peer-checked:from-night-top peer-checked:to-night-bottom peer-focus-visible:outline-2 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-focus"></span><span class="absolute top-2 left-3 size-[3px] rounded-full bg-white opacity-0 transition-opacity duration-300 peer-checked:opacity-85 motion-reduce:transition-none"></span><span class="absolute top-5 left-[22px] size-[3px] rounded-full bg-white opacity-0 transition-opacity duration-300 peer-checked:opacity-85 motion-reduce:transition-none"></span><span class="absolute top-3 left-[30px] size-[3px] rounded-full bg-white opacity-0 transition-opacity duration-300 peer-checked:opacity-85 motion-reduce:transition-none"></span><span class="pointer-events-none absolute top-1 left-1 size-7 rounded-full bg-sun shadow-[0_0_0_3px_rgba(253,230,138,.45)] transition-[translate,background-color,box-shadow] duration-300 peer-checked:translate-x-10 peer-checked:bg-moon peer-checked:shadow-[inset_-7px_-3px_0_0_#94a3b8] motion-reduce:transition-none"></span></label>
<label class="relative inline-block h-9 w-[76px] cursor-pointer"><input type="checkbox" role="switch" aria-label="Dark mode" class="peer sr-only" checked><span class="absolute inset-0 rounded-full bg-linear-to-b from-sky-top to-sky-bottom peer-checked:from-night-top peer-checked:to-night-bottom peer-focus-visible:outline-2 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-focus"></span><span class="absolute top-2 left-3 size-[3px] rounded-full bg-white opacity-0 transition-opacity duration-300 peer-checked:opacity-85 motion-reduce:transition-none"></span><span class="absolute top-5 left-[22px] size-[3px] rounded-full bg-white opacity-0 transition-opacity duration-300 peer-checked:opacity-85 motion-reduce:transition-none"></span><span class="absolute top-3 left-[30px] size-[3px] rounded-full bg-white opacity-0 transition-opacity duration-300 peer-checked:opacity-85 motion-reduce:transition-none"></span><span class="pointer-events-none absolute top-1 left-1 size-7 rounded-full bg-sun shadow-[0_0_0_3px_rgba(253,230,138,.45)] transition-[translate,background-color,box-shadow] duration-300 peer-checked:translate-x-10 peer-checked:bg-moon peer-checked:shadow-[inset_-7px_-3px_0_0_#94a3b8] motion-reduce:transition-none"></span></label></div></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#64748b] uppercase">Icon pair for a header</span><div class="flex flex-wrap items-center gap-[18px]">
<label class="relative inline-flex cursor-pointer items-center gap-2 rounded-full bg-[#e2e8f0] p-[5px]"><input type="checkbox" role="switch" aria-label="Dark mode" class="peer sr-only"><span class="absolute top-[5px] left-[5px] size-8 rounded-full bg-white shadow-[0_1px_3px_rgba(15,23,42,.2)] transition-transform duration-[220ms] peer-checked:translate-x-10 peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-focus motion-reduce:transition-none"></span><b aria-hidden="true" class="relative z-[2] grid size-8 place-items-center text-base">☀</b><b aria-hidden="true" class="relative z-[2] grid size-8 place-items-center text-base">☾</b></label>
<label class="relative inline-flex cursor-pointer items-center gap-2 rounded-full bg-[#e2e8f0] p-[5px]"><input type="checkbox" role="switch" aria-label="Dark mode" class="peer sr-only" checked><span class="absolute top-[5px] left-[5px] size-8 rounded-full bg-white shadow-[0_1px_3px_rgba(15,23,42,.2)] transition-transform duration-[220ms] peer-checked:translate-x-10 peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-focus motion-reduce:transition-none"></span><b aria-hidden="true" class="relative z-[2] grid size-8 place-items-center text-base">☀</b><b aria-hidden="true" class="relative z-[2] grid size-8 place-items-center text-base">☾</b></label></div></div>
CSS
@theme {
  --color-sky-top: #0284c7;
  --color-sky-bottom: #0369a1;
  --color-night-top: #1e293b;
  --color-night-bottom: #0f172a;
  --color-sun: #fde68a;
  --color-moon: #e2e8f0;
  --color-focus: #2563eb;
}

About this set

Theme switches for a light and dark mode setting. Sun to moon is a 76 pixel track with a blue sky: when it is switched on the knob slides across, the sky turns to night, three small stars fade in and the yellow sun becomes a grey crescent moon drawn with an inset shadow. The icon pair is a compact header control showing a sun and a moon glyph with a white disc that slides behind the active one, sized to sit next to navigation links. Use sun to moon where the switch is a feature of the page, such as a settings panel or a hero, and the icon pair in a site header where space is short. Both are a single checkbox with role=”switch” where checked means dark. The CSS only draws state, so wiring it to a real theme is a one-line change listener in your own script, or a :has() rule on the page. In Bootstrap the sun and moon are layered backgrounds on a stock .form-switch.

What’s included

  • Sun that turns into a crescent moon as the sky darkens
  • Stars that fade in on the night side
  • Compact sun and moon icon pair for a header bar
  • Deeper sky blue so the track and sun stand out from a light page
  • Checked means dark, ready to wire to your theme code

Accessibility

Each switch is a checkbox with role="switch" and the name Dark mode, so assistive technology reads its state as on or off. The sun and moon glyphs are aria-hidden. Tab focuses the control, Space toggles it, and a 2px blue outline marks focus. All transitions stop under prefers-reduced-motion.

Customise it

The sky, night, sun and moon colours are the gradient and background values in .dn i (plain CSS), the SVG fills and gradients on .dn .form-check-input (Bootstrap) or the --color-sky-*, --color-night-*, --color-sun and --color-moon theme colours (Tailwind).