Overview
Toggle switches built on a real <input type="checkbox"> with appearance: none so keyboard, screen-reader, and focus semantics still come from the native element. Three variants demonstrate the technique’s range: a Day/Night celestial pill, a neumorphic dial morph, and an industrial 12-LED power glow.
When to use it
Reach for toggle switches when the option is binary and the change applies immediately (no separate save action) — notification settings, dark mode, in-app feature flags. Skip them for binary decisions that need an explicit confirm (use checkbox + save button) and for non-binary options (use segmented control or radio).
How it works
The native <input type="checkbox" role="switch"> gets appearance: none to strip its default rendering. A wrapping <label> draws the track and thumb via a ::before (track background) and ::after (thumb). When :checked, the wrapper toggles a CSS custom property like --on: 1 via input:checked + label { --on: 1 } which the thumb animation reads: thumb transform: translateX(calc(var(--on) * var(--track-width))) slides between endpoints. Variant decorations (sun/moon, LEDs, neumorphic depth) attach as extra pseudo-element layers driven by the same state property.
Production gotchas
Forgetting role="switch" on the input means screen readers announce “checkbox” instead of “switch” — the semantic difference is small but real for AT users. The visually-hidden native input must still capture focus — do not use display: none or visibility: hidden; use opacity: 0; position: absolute so focus and click events still reach it. Thumb animations on tightly packed switches should clamp the thumb size at least 2px smaller than the track inset or rounding pushes the thumb outside the track on retina.
Accessibility
Native checkbox + role="switch" gives screen readers the right announcement and keyboard support (Space toggles) for free. Add an aria-label describing what the switch controls if the visible label is decorative-only. Under prefers-reduced-motion: reduce drop the slide transition so the thumb snaps to position. Verify focus ring visibility on both on and off states — the focused state must read distinct from the track.
References
Implementation depth
The checkbox or switch state should be the source of truth. The knob translation, track color, and icon swap are all visual reflections of a state that keyboard and assistive tech can already operate.
Do not hide focus behind the moving knob. A switch needs visible keyboard focus on the control itself, a label that explains the setting, and reduced motion that snaps the knob while keeping the state obvious.