A switch that is still a checkbox
CaveatStyle the input itself rather than hiding it behind a div. appearance: none strips the paint and keeps everything else — focus, the space key, the label association, the announced role.
FallbackWhere the styling is unsupported you get the platform checkbox. It is not the design, but it is a working control, which a styled div would not be.
input[type="checkbox"] {
/* paint gone, semantics kept */
appearance: none;
width: 44px; height: 25px;
border-radius: 999px;
}
input:checked::after { translate: 19px 0; }
Published
Questions
Can you use ::before and ::after on a checkbox?
Only once appearance: none has removed the native widget. Before that, form controls are replaced elements and browsers do not reliably draw pseudo-elements on them. After it, the input is an ordinary box and ::after works as the sliding knob.
Should a toggle switch use role="switch"?
It can. Adding role="switch" to the checkbox makes screen readers announce on and off instead of checked and not checked, and the keyboard and checked state keep working. Leave it off and the control is still an honest checkbox.
Why does my custom checkbox ignore the space key?
It is probably a styled <div> or <span> with the real input hidden or missing. Only a native <input type="checkbox"> toggles on space and takes focus for free, so style that input directly.