Component Deep Dive #26: Toggle Switch
A good toggle works without thinking. A bad one takes three clicks before the user realizes it's interactive.
Core: Checkbox + Label, Zero JavaScript
.toggle__input:checked + .toggle__track {
background: #6366f1;
}
.toggle__input:checked + .toggle__track .toggle__thumb {
transform: translateX(20px);
}
The entire animation is driven by :checked. The checkbox itself is hidden with opacity: 0 (NOT display: none - that removes it from the accessibility tree). The label wraps everything, so clicking anywhere toggles the state.
Why Not display: none?
display: none removes the element from the accessibility tree entirely - keyboard users can't Tab to it, screen readers can't see it. Use position: absolute; opacity: 0; width: 0; height: 0; instead: visually hidden, but still in the accessibility tree.
Keyboard Focus
Use :focus-visible instead of :focus - the former only shows the focus ring during keyboard navigation, not on mouse click. This is modern CSS best practice.
RTL Support
In right-to-left languages, the toggle direction should reverse. Use logical properties or [dir="rtl"] selectors.
Common Pitfalls
- Forgetting
role="switch"- checkbox defaults torole="checkbox", but switch is more semantic - Using
display: none- removes from accessibility tree - Hardcoded
translateX- must recalculate when changing track/thumb sizes - No disabled state styling - disabled toggles look identical to active ones
-
transition: all- poor performance, only transition specific properties
The toggle switch proves that with CSS, you can build a fully accessible, animated, interactive component with zero JavaScript.
This article was first published on Deskless Daily. Follow for more AI-driven tech content.
Top comments (0)