Eight toggle switches built on real checkbox and radio inputs, so they work with the keyboard, submit with forms and are announced as switches by screen readers. Each one is pure CSS apart from the label text, and every design shows a clear focus ring.
The familiar rounded switch, built from a real checkbox with role="switch" so screen readers announce it as on or off. The thumb slides with a transform and the track changes colour, and a visible focus ring appears for keyboard users only.
A wider track that spells out its state, so the meaning never depends on colour alone. The ON and OFF words are drawn with pseudo-elements and swap sides as the thumb moves, which helps people with colour vision deficiency read the state at a glance.
A dark-mode switch whose thumb carries the icon: a sun when light is selected and a moon, cut out with a second circle, when dark is selected. The page label stays hidden visually but is read aloud, and the icons are pure CSS gradients with no images.
A squared-off switch with a ridged knob, inspired by physical rocker switches on studio equipment. Corners stay sharp, the knob gets three grip lines from a repeating gradient, and the checked state uses a strong dark fill instead of a bright colour.
A switch for dark interfaces where the active state glows. Layered box-shadows create the halo around both the track and the thumb, and the colour moves from a dim violet outline to a bright cyan when it is turned on.
A realistic settings panel: each row has a title, a one-line explanation and a switch on the right. The description is tied to its switch with aria-describedby, so assistive technology reads the explanation after the label instead of losing it.
View code
<section class="set">
<h2>Notifications</h2>
<div class="row">
<div><p class="t" id="s1">Order updates</p><p class="d" id="s1d">When an order ships or is delivered.</p></div>
<input type="checkbox" role="switch" aria-labelledby="s1" aria-describedby="s1d" checked>
</div>
<div class="row">
<div><p class="t" id="s2">Weekly report</p><p class="d" id="s2d">A summary of sales every Monday morning.</p></div>
<input type="checkbox" role="switch" aria-labelledby="s2" aria-describedby="s2d">
</div>
<div class="row">
<div><p class="t" id="s3">Low stock alerts</p><p class="d" id="s3d">When any product falls below 5 units.</p></div>
<input type="checkbox" role="switch" aria-labelledby="s3" aria-describedby="s3d" checked>
</div>
</section>
One switch in three sizes driven by a single custom property. Change --s on the element and the track, thumb and travel distance all scale together, which keeps a design system consistent without writing three separate rule sets.
The two-option toggle used above pricing tables. It is built from two radio buttons inside a fieldset, so arrow keys move between Monthly and Yearly, and a sliding highlight is positioned with the :has() selector so no JavaScript is needed.
A switch is a checkbox with a different look. Using <input type="checkbox" role="switch"> gives you keyboard support with Space, a checked state the browser remembers, and form submission, with no JavaScript. Styling it with appearance: none keeps all of that while letting you draw the track and thumb yourself.
Drawing the track and thumb
The input itself becomes the track, and a ::before pseudo-element becomes the thumb. On :checked the track changes colour and the thumb moves with transform: translateX(), which animates smoothly because transforms do not trigger layout. Keep the travel distance equal to the track width minus the thumb width and both paddings.
Do not rely on colour
Green for on and grey for off is not enough for people with colour vision deficiency. The On / Off and icon designs here add text or a symbol, and the position of the thumb is a second cue. If a switch takes effect immediately, say so in the label; if it needs a Save button, a checkbox is often clearer.
Switch or checkbox?
Use a switch when the change happens straight away, such as turning notifications on. Use a checkbox inside a form that is submitted later, and radio buttons when there are two named options like Monthly and Yearly, as in the billing toggle demo.
Frequently asked questions
Do these switches need JavaScript?
No. Every switch here works with CSS alone; the billing toggle uses the :has() selector to move its highlight.
Are they accessible?
They use real inputs with role="switch" or radio buttons, visible labels and :focus-visible outlines, so keyboard and screen reader users can operate them.
Can I change the size?
Yes. The size scale demo drives the track, thumb and travel from one custom property.