CSS Switch Generator
iOS-style toggle switches with fully custom styling.
<label class="css-switch">
<input type="checkbox" checked />
<span class="track"></span>
<span>Dark mode</span>
</label>
<style>
.css-switch {
display: inline-flex;
align-items: center;
gap: 10px;
cursor: pointer;
}
.css-switch input {
position: absolute;
opacity: 0;
pointer-events: none;
}
.css-switch .track {
position: relative;
display: inline-block;
width: 52px;
height: 28px;
background: #C1C9D2;
border-radius: 28px;
transition: background 180ms cubic-bezier(0.22, 1, 0.36, 1);
}
.css-switch .track::after {
content: "";
position: absolute;
top: 3px;
left: 3px;
width: 22px;
height: 22px;
background: #FFFFFF;
border-radius: 50%;
box-shadow: 0 1px 2px rgba(0,0,0,0.2), 0 1px 3px rgba(0,0,0,0.1);
transition: transform 180ms cubic-bezier(0.22, 1, 0.36, 1);
}
.css-switch input:checked + .track {
background: #635BFF;
}
.css-switch input:checked + .track::after {
transform: translateX(24px);
}
.css-switch input:focus-visible + .track {
box-shadow: 0 0 0 3px #635BFF33;
}
</style>What is a CSS Switch Generator?
A CSS toggle switch (also called a toggle, flip-switch, or iOS-style switch) is a styled boolean control that flips between on and off states. It's the go-to control for settings that apply immediately — dark mode, notifications, feature toggles, "remember me" on login forms — where the user wants a single click and immediate effect rather than a checkbox plus Save button.
Switch vs checkbox. Use a switch when toggling the state has an immediate consequence (the app changes now). Use a checkbox when the state is a selection that's submitted later with a form, or when multiple items are chosen from a set. Mixing them confuses users — a "Save" button next to a switch is a smell.
Implementation pattern. Same as custom checkboxes: hide the native <input type="checkbox"> visually but keep it focusable and form-submittable. Style a sibling .track element with background that changes under :checked, and use a ::after pseudo-element as the circular thumb that slides via translateX(). The native input provides keyboard access (space to toggle) and screen-reader compatibility.
Easing matters. The thumb slide is what makes a switch feel "premium" or cheap. A cubic-bezier(0.22, 1, 0.36, 1) curve (the "Stripe pop") gives a crisp, responsive feel — steep start, decisive stop. Avoidlinear (mechanical) and overly-long durations (> 250ms feels sluggish). Default to 180ms with a Stripe-style ease-out curve.
Accessibility. The native checkbox is still present so screen readers announce it correctly. Add role="switch" and aria-checked on the wrapper if you want screen readers to announce it as a switch rather than a checkbox — the HTML spec added the implicit role="switch" for <input type="checkbox" role="switch"> in 2020, so modern browsers handle this correctly.
Colour choice. The on-state colour should match your brand accent (the default #635BFF here is simpletool.io's). The off-state colour should be neutral grey — reserving your accent for the meaningful state (on). Make sure both states pass contrast requirements against the surrounding background.
How to generate a CSS toggle switch
- Pick width and height. 52×28 is the classic iOS size.
- Set the on, off, and thumb colours to match your brand.
- Copy the HTML + CSS and paste into your component library.
Features
- Dimensions slider + colour pickers for all three states.
- Native input preserved for accessibility.
- Stripe-style easing for a crisp slide feel.
- Focus-visible ring for keyboard users.
- Copy-ready HTML + CSS snippet.
Frequently asked questions
- When should I use a switch instead of a checkbox?
- Use a switch when toggling has an immediate effect — settings, feature toggles, dark mode. Use a checkbox when the state is a selection submitted later with a form. A Save button next to a switch is a design smell.
- How do I make the switch accessible?
- Our generator keeps the native <input type="checkbox"> in the DOM — it's just visually hidden. Screen readers announce it correctly. For explicit 'switch' role, add role="switch" to the input, which modern browsers honour.
- What duration feels best for the slide?
- 150–200ms with an ease-out curve (cubic-bezier(0.22, 1, 0.36, 1) works great). Faster feels abrupt, slower feels sluggish. Our default is 180ms.
- Can I make it keyboard accessible?
- Yes — the native input is focusable and space-bar toggles it. We add a focus-visible ring so keyboard users see where focus is.