Open demo

CSS code

HTML
<div><span class="lbl">Soft pill</span><div class="row">
<label class="nb"><input type="checkbox" role="switch" aria-label="Sound" checked><i></i></label>
<label class="nb"><input type="checkbox" role="switch" aria-label="Vibration"><i></i></label></div></div>
<div><span class="lbl">Push button</span><div class="row">
<label class="np"><input type="checkbox" aria-label="Power" checked><i aria-hidden="true">⏻</i></label>
<label class="np"><input type="checkbox" aria-label="Power"><i aria-hidden="true">⏻</i></label></div></div>
<div><span class="lbl">Inset track</span><div class="row">
<label class="ns"><input type="checkbox" role="switch" aria-label="Auto-brightness" checked><i></i></label>
<label class="ns"><input type="checkbox" role="switch" aria-label="Night shift"><i></i></label></div></div>
CSS
/* Soft switches: a visually hidden checkbox followed by an <i> drawn with paired light/dark shadows.
   They only read correctly on the matching #e6e9ef ground. */
.nb input,.np input,.ns input{position:absolute;opacity:0;width:0;height:0;margin:0}
.nb{position:relative;display:inline-block;width:76px;height:38px;cursor:pointer}
.nb i{position:absolute;inset:0;border-radius:999px;background:#e6e9ef;
  box-shadow:inset 3px 3px 7px #c5c9d1,inset -3px -3px 7px #fff;transition:box-shadow .28s}
.nb i::before{content:"";position:absolute;top:5px;left:5px;width:28px;height:28px;border-radius:50%;
  background:#eef1f6;box-shadow:2px 2px 5px #c5c9d1,-2px -2px 5px #fff;transition:transform .28s,background .28s}
.nb input:checked+i::before{transform:translateX(38px);background:#2563eb}
/* push button */
.np{position:relative;width:64px;height:64px;display:inline-block;cursor:pointer}
.np i{position:absolute;inset:0;border-radius:50%;background:#e6e9ef;display:grid;place-items:center;
  box-shadow:5px 5px 11px #c5c9d1,-5px -5px 11px #fff;transition:box-shadow .28s,color .28s;
  color:#5b6475;font-size:1.25rem;font-style:normal}
.np input:checked+i{box-shadow:inset 4px 4px 9px #c5c9d1,inset -4px -4px 9px #fff;color:#1d4ed8}
/* slim inset track */
.ns{position:relative;display:inline-block;width:64px;height:22px;cursor:pointer}
.ns i{position:absolute;inset:0;border-radius:999px;background:#e6e9ef;
  box-shadow:inset 2px 2px 5px #c5c9d1,inset -2px -2px 5px #fff}
.ns i::before{content:"";position:absolute;top:-6px;left:0;width:34px;height:34px;border-radius:50%;
  background:#eef1f6;box-shadow:2px 2px 6px #c5c9d1,-2px -2px 6px #fff;transition:transform .28s,background .28s}
.ns input:checked+i::before{transform:translateX(30px);background:#15803d}
.nb input:focus-visible+i,.np input:focus-visible+i{outline:2px solid #2563eb;outline-offset:3px}
.ns input:focus-visible+i{outline:2px solid #2563eb;outline-offset:9px}
@media (prefers-reduced-motion:reduce){.nb i,.nb i::before,.np i,.ns i::before{transition:none}}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Soft pill</span><div class="demo-row">
<div class="form-check form-switch nb"><input class="form-check-input" type="checkbox" role="switch" aria-label="Sound" checked></div>
<div class="form-check form-switch nb"><input class="form-check-input" type="checkbox" role="switch" aria-label="Vibration"></div></div></div>
<div><span class="lbl">Push button</span><div class="demo-row">
<div class="np"><input type="checkbox" class="btn-check" id="np-power-1" aria-label="Power" checked><label class="btn d-grid rounded-circle" for="np-power-1"><span aria-hidden="true" class="m-auto">⏻</span></label></div>
<div class="np"><input type="checkbox" class="btn-check" id="np-power-2" aria-label="Power"><label class="btn d-grid rounded-circle" for="np-power-2"><span aria-hidden="true" class="m-auto">⏻</span></label></div></div></div>
<div><span class="lbl">Inset track</span><div class="demo-row">
<label class="ns"><input class="visually-hidden" type="checkbox" role="switch" aria-label="Auto-brightness" checked><i></i></label>
<label class="ns"><input class="visually-hidden" type="checkbox" role="switch" aria-label="Night shift"><i></i></label></div></div>
CSS
/* Soft switches on the matching #e6e9ef ground. Pill = Bootstrap .form-switch (knob drawn by --bs-form-switch-bg),
   push button = .btn-check + .btn, inset track = a .visually-hidden checkbox and an <i>. */
.nb{--nb-knob:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-19 -19 38 38'><filter id='s' x='-50%25' y='-50%25' width='200%25' height='200%25'><feDropShadow in='SourceGraphic' dx='2' dy='2' stdDeviation='2.5' flood-color='%23c5c9d1' result='a'/><feDropShadow in='SourceGraphic' dx='-2' dy='-2' stdDeviation='2.5' flood-color='%23fff' result='b'/><feMerge><feMergeNode in='a'/><feMergeNode in='b'/><feMergeNode in='SourceGraphic'/></feMerge></filter><circle r='14' fill='%23eef1f6' filter='url(%23s)'/></svg>");
  --nb-knob-on:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-19 -19 38 38'><filter id='s' x='-50%25' y='-50%25' width='200%25' height='200%25'><feDropShadow in='SourceGraphic' dx='2' dy='2' stdDeviation='2.5' flood-color='%23c5c9d1' result='a'/><feDropShadow in='SourceGraphic' dx='-2' dy='-2' stdDeviation='2.5' flood-color='%23fff' result='b'/><feMerge><feMergeNode in='a'/><feMergeNode in='b'/><feMergeNode in='SourceGraphic'/></feMerge></filter><circle r='14' fill='%232563eb' filter='url(%23s)'/></svg>");
  display:inline-block;min-height:0;margin:0;padding:0;line-height:0}
.nb .form-check-input{width:76px;height:38px;margin:0;float:none;border:0;border-radius:999px;cursor:pointer;
  background-color:#e6e9ef;transition:background-position .28s}
.nb .form-check-input,.nb .form-check-input:focus{--bs-form-switch-bg:var(--nb-knob);
  box-shadow:inset 3px 3px 7px #c5c9d1,inset -3px -3px 7px #fff}
.nb .form-check-input:checked{--bs-form-switch-bg:var(--nb-knob-on);background-color:#e6e9ef}
.nb .form-check-input:focus-visible{outline:2px solid #2563eb;outline-offset:3px}
/* push button */
.np .btn{--np-shadow:5px 5px 11px #c5c9d1,-5px -5px 11px #fff;--bs-btn-padding-x:0;--bs-btn-padding-y:0;--bs-btn-border-width:0;
  --bs-btn-font-size:1.25rem;--bs-btn-line-height:1;--bs-btn-bg:#e6e9ef;--bs-btn-color:#5b6475;--bs-btn-hover-bg:#e6e9ef;
  --bs-btn-hover-color:#5b6475;--bs-btn-active-bg:#e6e9ef;--bs-btn-active-color:#1d4ed8;
  width:64px;height:64px;box-shadow:var(--np-shadow);transition:box-shadow .28s,color .28s}
.np .btn-check:checked+.btn{--np-shadow:inset 4px 4px 9px #c5c9d1,inset -4px -4px 9px #fff}
.np .btn-check:focus-visible+.btn{box-shadow:var(--np-shadow);outline:2px solid #2563eb;outline-offset:3px}
/* slim inset track */
.ns{position:relative;display:inline-block;width:64px;height:22px;cursor:pointer}
.ns i{position:absolute;inset:0;border-radius:999px;background:#e6e9ef;
  box-shadow:inset 2px 2px 5px #c5c9d1,inset -2px -2px 5px #fff}
.ns i::before{content:"";position:absolute;top:-6px;left:0;width:34px;height:34px;border-radius:50%;
  background:#eef1f6;box-shadow:2px 2px 6px #c5c9d1,-2px -2px 6px #fff;transition:transform .28s,background .28s}
.ns input:checked+i::before{transform:translateX(30px);background:#15803d}
.ns input:focus-visible+i{outline:2px solid #2563eb;outline-offset:9px}
@media (prefers-reduced-motion:reduce){.nb .form-check-input,.np .btn,.ns i::before{transition:none}}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-soft-muted uppercase">Soft pill</span><div class="flex flex-wrap items-center gap-[18px]">
<label class="relative inline-block h-[38px] w-[76px] cursor-pointer"><input type="checkbox" role="switch" aria-label="Sound" class="peer sr-only" checked><span class="absolute inset-0 rounded-full bg-soft shadow-soft-in peer-focus-visible:outline-2 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-soft-blue"></span><span class="pointer-events-none absolute top-[5px] left-[5px] size-7 rounded-full bg-soft-knob shadow-soft-knob transition-[translate,background-color] duration-[280ms] peer-checked:translate-x-[38px] peer-checked:bg-soft-blue motion-reduce:transition-none"></span></label>
<label class="relative inline-block h-[38px] w-[76px] cursor-pointer"><input type="checkbox" role="switch" aria-label="Vibration" class="peer sr-only"><span class="absolute inset-0 rounded-full bg-soft shadow-soft-in peer-focus-visible:outline-2 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-soft-blue"></span><span class="pointer-events-none absolute top-[5px] left-[5px] size-7 rounded-full bg-soft-knob shadow-soft-knob transition-[translate,background-color] duration-[280ms] peer-checked:translate-x-[38px] peer-checked:bg-soft-blue motion-reduce:transition-none"></span></label></div></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-soft-muted uppercase">Push button</span><div class="flex flex-wrap items-center gap-[18px]">
<label class="relative inline-block size-16 cursor-pointer"><input type="checkbox" aria-label="Power" class="peer sr-only" checked><span aria-hidden="true" class="absolute inset-0 grid place-items-center rounded-full bg-soft text-[1.25rem] text-soft-muted shadow-soft-out transition-[box-shadow,color] duration-[280ms] peer-checked:text-soft-ink-blue peer-checked:shadow-soft-press peer-focus-visible:outline-2 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-soft-blue motion-reduce:transition-none">⏻</span></label>
<label class="relative inline-block size-16 cursor-pointer"><input type="checkbox" aria-label="Power" class="peer sr-only"><span aria-hidden="true" class="absolute inset-0 grid place-items-center rounded-full bg-soft text-[1.25rem] text-soft-muted shadow-soft-out transition-[box-shadow,color] duration-[280ms] peer-checked:text-soft-ink-blue peer-checked:shadow-soft-press peer-focus-visible:outline-2 peer-focus-visible:outline-offset-3 peer-focus-visible:outline-soft-blue motion-reduce:transition-none">⏻</span></label></div></div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-soft-muted uppercase">Inset track</span><div class="flex flex-wrap items-center gap-[18px]">
<label class="relative inline-block h-[22px] w-16 cursor-pointer"><input type="checkbox" role="switch" aria-label="Auto-brightness" class="peer sr-only" checked><span class="absolute inset-0 rounded-full bg-soft shadow-soft-in-sm peer-focus-visible:outline-2 peer-focus-visible:outline-offset-[9px] peer-focus-visible:outline-soft-blue"></span><span class="pointer-events-none absolute -top-1.5 left-0 size-[34px] rounded-full bg-soft-knob shadow-soft-knob-lg transition-[translate,background-color] duration-[280ms] peer-checked:translate-x-[30px] peer-checked:bg-soft-green motion-reduce:transition-none"></span></label>
<label class="relative inline-block h-[22px] w-16 cursor-pointer"><input type="checkbox" role="switch" aria-label="Night shift" class="peer sr-only"><span class="absolute inset-0 rounded-full bg-soft shadow-soft-in-sm peer-focus-visible:outline-2 peer-focus-visible:outline-offset-[9px] peer-focus-visible:outline-soft-blue"></span><span class="pointer-events-none absolute -top-1.5 left-0 size-[34px] rounded-full bg-soft-knob shadow-soft-knob-lg transition-[translate,background-color] duration-[280ms] peer-checked:translate-x-[30px] peer-checked:bg-soft-green motion-reduce:transition-none"></span></label></div></div>
CSS
@theme {
  --color-soft: #e6e9ef;
  --color-soft-knob: #eef1f6;
  --color-soft-muted: #5b6475;
  --color-soft-blue: #2563eb;
  --color-soft-ink-blue: #1d4ed8;
  --color-soft-green: #15803d;
  --shadow-soft-in: inset 3px 3px 7px #c5c9d1, inset -3px -3px 7px #fff;
  --shadow-soft-in-sm: inset 2px 2px 5px #c5c9d1, inset -2px -2px 5px #fff;
  --shadow-soft-press: inset 4px 4px 9px #c5c9d1, inset -4px -4px 9px #fff;
  --shadow-soft-out: 5px 5px 11px #c5c9d1, -5px -5px 11px #fff;
  --shadow-soft-knob: 2px 2px 5px #c5c9d1, -2px -2px 5px #fff;
  --shadow-soft-knob-lg: 2px 2px 6px #c5c9d1, -2px -2px 6px #fff;
}

About this set

Switches drawn with paired light and dark shadows instead of borders, in the soft or neumorphic style, on a matched #e6e9ef grey ground. The soft pill has an inset track and a raised knob that turns blue as it slides across. The push button is a 64 pixel round button with a power glyph that looks raised when off and pressed in when on, with the glyph turning blue. The inset track is a slim 22 pixel groove with an oversized 34 pixel knob that turns green, a shape that reads well on touch devices. Use them in dashboards, smart home and music interfaces that already use the soft style, since the shadows only work on the matching background colour. Each control is a visually hidden checkbox followed by an element whose box shadows change with :checked. In Bootstrap the pill is a .form-switch with an SVG knob and the push button is a .btn-check with a .btn, and in Tailwind the shadows are theme tokens.

What’s included

  • Soft pill, push button and slim inset track
  • Raised and pressed states drawn with paired shadows
  • Power glyph darkened so it reaches 4.5:1 on the grey ground
  • Knob colour marks the on state, not only the shadow
  • Shadow values stored as Tailwind theme tokens

Accessibility

The switches use role="switch" and the push buttons are checkboxes named Power, each with an aria-label. Tab and Space work as for any checkbox, and focus draws a 2px blue outline around the visible control, widened on the inset track so it clears the large knob. The soft style keeps low-contrast edges by design, so the on state is also shown by the knob or glyph colour. Transitions are removed under prefers-reduced-motion.

Customise it

The ground colour #e6e9ef and the shadow colours #c5c9d1 and white must change together; they are in .nb, .np and .ns (plain CSS and Bootstrap) and in the --color-soft and --shadow-soft-* theme tokens (Tailwind). The on colours are #2563eb, #1d4ed8 and #15803d.