A properly built CSS checkbox is a styled native input type="checkbox", not a div dressed up like one. The browser keeps full control over checked state, keyboard activation with Space, focus management, and form participation; CSS only changes what the user sees. The standard technique is to apply appearance: none (sometimes written -webkit-appearance: none) to strip the browser's default drawing, then redraw the box with width, height, border, border-radius, and three colors: the unchecked background, the accent or checked background, and the checkmark color. The mark itself is typically a rotated pseudo-element built from right and bottom borders so it scales with the box size. Because the underlying element is still a real checkbox, label association, form submission, and assistive-technology support all keep working as long as you keep a visible label nested around the input or point a for attribute at its id. The CSS Checkbox Generator wraps this technique in a live preview that enforces sensible numeric ranges, so you can copy the resulting stylesheet and HTML without re-deriving any of the math.

What "Make a Checkbox in CSS" Actually Means
The phrase "make a checkbox in CSS" usually means one of two things. Most readers want a checkbox they can drop into an existing form without losing keyboard, focus, label-click, and form-submission behavior. A smaller subset wants a standalone checkbox used as a UI toggle, the way CSS checkbox hacks drive accordions and slideshows. Both rely on the same starting point: keep the native input type="checkbox" and let CSS handle only what the box looks like. The native element gives you checked state, indeterminate support, focus management, Space activation, and assistive-technology support for free. Replacing it with a styled div means rebuilding all of that by hand, which is why almost every accessible CSS-checkbox guide ends up back at the native input.
The CSS Checkbox Generator sits firmly in the first camp. It styles a real checkbox, exposes the exact CSS class and HTML it uses in the preview, and rejects out-of-range geometry or malformed color values so you cannot accidentally copy broken code into production.
Native Input or Custom Div: What the CSS Replaces
The minimum CSS to replace the browser's checkbox drawing is well documented. MDN's appearance reference explains that appearance: none removes platform-native styling so authors can replace it, and the W3C CSS Basic User Interface Level 4 spec defines the same behavior at the standards level. Combined with -webkit-appearance: none for Safari, this single declaration is what makes custom styling possible at all. Everything after that is just ordinary CSS for box, border, and a checkmark.
The temptation is to skip the native input and use a div instead. Doing so forces you to fake checked state with class toggles, manage keyboard activation with JavaScript, and explain the role to screen readers with ARIA. The native input already does all of that correctly; suppressing its visual rendering with appearance: none keeps every one of those behaviors intact while still letting you redesign the box, the checkmark, and the focus ring.
If your real concern is making a checkbox look consistent across operating systems, the native-input route is also the only one that survives user settings such as Windows High Contrast and forced colors. A custom div loses that compatibility by default.
Generator Inputs and Their Valid Ranges
The CSS Checkbox Generator exposes six inputs: square size, border width, corner radius, accent color, background color, and checkmark color. Each has a strict range that the generator enforces, so the CSS you copy is always internally consistent. The exact bounds are worth knowing before you start dragging sliders.
| Input | Accepted values | Notes |
|---|---|---|
| Size | 16 to 64 px (whole pixels) | Includes the visible border because the output sets box-sizing: border-box. |
| Border | 1 to 6 px (whole pixels) | Drives the visible stroke around the box. |
| Corner radius | 0 to 50% | At 50% the box becomes a circle at any supported size. |
| Accent, background, checkmark | 6-digit HEX only (no shorthand, no RGB) | The browser color picker and numeric controls feed valid values; malformed colors are rejected. |
The strictness is deliberate. Decimals where integers are required, partial HEX values, and out-of-range geometry all produce misleading code, so the generator simply refuses them. In practice this means the only way to get broken values out of the tool is to edit the copied CSS by hand after the fact, at which point any rendering problem is yours to debug, not the tool's. Generation and copying happen entirely in the current browser tab, with no account, upload, stylesheet service, or saved design state.
Style a Native Checkbox Step by Step
- Open the CSS Checkbox Generator in your browser. Everything runs in the current tab; no account, upload, or saved design state is involved.
- Set the square size between 16 and 64 px, the border between 1 and 6 px, and the corner radius between 0 and 50%. The live preview updates as you change any value, so you can compare side by side without committing to numbers first.
- Pick the three colors with the browser's color controls: accent (used for the checked fill and the focus-visible outline), background (the unchecked fill), and checkmark (the rotated mark drawn with a ::after pseudo-element). All three must be six-digit HEX values such as #1f6feb.
- Click the box or its preview label to confirm both the checked and unchecked states render as you expect. The preview uses the exact generated stylesheet in a scoped class named lizely-checkbox, so what you see is exactly what will render in production.
- Copy the CSS block and paste it into your stylesheet. Rename the class if you need a different namespace, but keep the structural pieces in place: box-sizing: border-box, cursor: pointer, relative positioning for the pseudo-element, and the :focus-visible outline rule.
- Copy the HTML block and replace the example label text with the wording of your real form choice. Keep the input type="checkbox" inside a label element so click-target, accessible name, and keyboard focus all work without extra attributes.
- In the destination form, test Tab order, Space activation, and the focus-visible outline against the actual surrounding background. Adjust the outline color or width in your own stylesheet if your theme needs different contrast against the page.
If you use a framework, translate class to className and connect checked and onChange as the framework requires, but do not replace the native input with a div or move the label association out of the wrapping label. Those two structural choices are what keep the checkbox accessible. The output HTML deliberately contains no inline script; checkbox state is managed by the browser and the surrounding form.
Customizing the Checkmark With a Pseudo-Element
The mark itself deserves its own section because it is the part most hand-rolled CSS checkbox tutorials get wrong. The CSS Checkbox Generator draws the checkmark with a single ::after pseudo-element that is only visible while :checked is true. Its width, height, and border thickness scale from the chosen box size, with minimum values that keep the mark legible at the smallest supported size of 16 px.
Three details are deliberate product choices rather than universal rules. First, the mark uses only the right and bottom borders, which gives the classic checkmark shape without an SVG dependency. Second, the pseudo-element rotates forty-five degrees and is positioned from proportional offsets so it stays centered as the box grows. Third, the border thickness is proportional to the box size, so the mark never looks too thin at 64 px or too heavy at 16 px. At unusual zoom levels, device pixel ratios, or extreme border settings, antialiasing may make one edge appear slightly heavier, which is a rendering artifact rather than a bug.
If you want to change those ratios, such as a heavier mark or a different angle, edit the copied CSS in your own stylesheet rather than expecting the generator to expose new controls. The ratios are covered by exact string and geometry tests inside the tool, not presented as externally mandated values, so the cleanest workflow is to treat the generator's output as a starting point and refine from there.
Accessibility Checks That Belong in Your Real Form
A visually attractive checkbox is not automatically accessible. The generator handles unchecked, checked, and :focus-visible styling, and the embedded preview is an honest reflection of those three states. It does not simulate indeterminate, invalid, required, disabled, read-only, high-contrast, or forced-colors states. Those have to be added and verified in the destination form using real content.
| Concern | Covered by the generator | Needs manual work in the form |
|---|---|---|
| Unchecked, checked, focus-visible styles | Yes | Confirm outline contrast against the actual page background. |
| Disabled, invalid, required, indeterminate | No | Add via framework primitives and verify with assistive tech. |
| Keyboard navigation (Tab, Space) | Native input keeps it | Test real Tab order and instructions in the live form. |
| Forced colors (Windows High Contrast etc.) | Browser decides | Verify and avoid suppressing overrides without a strong reason. |
| 200% zoom and small viewports | Box sizing scales | Confirm the mark stays legible and the click target is usable. |
The minimum checklist before shipping is short. Tab through the form and confirm the focus-visible outline appears on the checkbox itself, not skipped past it. Press Space on a focused checkbox and confirm the checked state toggles without a click. Check the contrast of the focus indicator against the surrounding background, not just the box; the Color Contrast Checker is the right tool for that step. Render the form at 200 percent zoom and confirm the mark remains legible. Toggle Windows High Contrast or macOS Increase Contrast and confirm forced colors do not destroy the control. The MDN appearance reference and the W3C CSS UI spec explain why operating systems are allowed to override custom colors, and that behavior is often worth keeping rather than fighting.
If any of those checks fail, fix the surrounding form rather than rewriting the generated stylesheet. The CSS Checkbox Generator's job is to give you a clean native baseline that preserves a real input type="checkbox" with an accessible label relationship; the form's job is to provide context, instructions, and error handling around it.
Related reading: How to Use Cubic Bezier CSS for Custom Easing.