What the form elements generator does
Native checkboxes and switches look different in every browser and are hard to style directly. This generator produces custom checkboxes and toggle switches that keep the real <input> underneath — so keyboard access, form submission, labels and screen readers keep working — while the visible control is drawn with CSS in your colours and size. Preview, adjust, copy. Runs in your browser.
The pattern: real input, custom visual
<label class="check">
<input type="checkbox" class="check__input">
<span class="check__box" aria-hidden="true"></span>
Remember me
</label>
.check__input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.check__box { width: 20px; height: 20px; border: 2px solid #999; border-radius: 4px; }
.check__input:checked + .check__box { background: #E85D26; border-color: #E85D26; }
.check__input:checked + .check__box::after { content: ""; /* draw the tick */ }
.check__input:focus-visible + .check__box { outline: 3px solid #E85D2666; outline-offset: 2px; }The input is visually hidden but not display: none (which would remove it from the tab order). The sibling span draws the box, and :checked + styles it. Because everything is inside a <label>, clicking the text or the box toggles the input.
Toggle switch
.switch__track { width: 44px; height: 24px; border-radius: 12px; background: #ccc; transition: background .2s; }
.switch__track::after { content: ""; width: 20px; height: 20px; border-radius: 50%; background: #fff;
transform: translateX(2px); transition: transform .2s; }
.switch__input:checked + .switch__track { background: #E85D26; }
.switch__input:checked + .switch__track::after { transform: translateX(22px); }A switch is a checkbox with different semantics: it should apply immediately (turning a setting on) rather than waiting for a submit button. Add role="switch" to the input so screen readers announce “on/off” instead of “checked/unchecked”.
Checkbox or switch?
| Use a checkbox when | Use a switch when |
|---|---|
| The choice is part of a form submitted later | The change takes effect immediately |
| Several options can be selected in a list | It is a single on/off setting |
| Agreeing to terms, selecting items | Notifications, dark mode, Wi-Fi |
| An indeterminate state is possible | There are only two states |
Accessibility checklist
- Keep the native input in the DOM and focusable; never replace it with a div.
- Always associate a label — wrapping, or
for/id. The label is the click target and the accessible name. - Show a visible focus indicator on the custom visual via
:focus-visible. - Do not rely on colour alone for the checked state: the tick mark or knob position must be visible in greyscale.
- Minimum touch target 44 × 44 px — pad the label if the box is small.
- Respect
prefers-reduced-motionby shortening or removing the knob transition.
The modern alternative: accent-color and appearance
For simple recolouring, accent-color: #E85D26 on the native input tints the browser's own checkbox, radio and switch-like controls in one line, keeping full native behaviour. For full custom drawing without a sibling element, appearance: none on the input lets you style the input itself with ::before for the tick. Both are supported in all current browsers. The sibling-span pattern this generator uses remains the most flexible and predictable across browsers, and it works with older ones.