CSS Checkbox Generator
Design a custom checkbox style visually, then copy the HTML + CSS.
About This Tool
The generator hides the browser's default checkbox with appearance: none, then draws a custom box and checkmark on top that respond to :checked. It's still a real <input type="checkbox"> underneath, so keyboard navigation and screen readers keep working as expected.
Why appearance: none is necessary at all
Native form controls like checkboxes are rendered by the operating system's own UI toolkit, not by the browser's normal CSS box model, which is why a plain checkbox looks slightly different on Windows, macOS, and Android and historically resisted most CSS styling attempts. Setting appearance: none tells the browser to stop drawing that OS-native widget and instead treat the element as a plain styleable box, which is what makes properties like border, border-radius, and background actually take effect on a checkbox. The generator also outputs the older -webkit-appearance: none alongside the unprefixed property, since some WebKit-based browsers historically needed the prefixed version to fully suppress native checkbox chrome, even though the unprefixed property has been standard for years.
How the checkmark is drawn without an image or icon font
The tick mark isn't an SVG, emoji, or icon font glyph, it's a CSS border trick applied to the box's ::after pseudo-element. The pseudo-element is given a border on only two sides, bottom and right (border-width: 0 2px 2px 0), which by itself just looks like an upside-down "L" shape. Rotating that shape 45 degrees with transform: rotate(45deg) turns it into a checkmark tick. This technique needs zero extra HTTP requests and scales to any color instantly since it just inherits whatever border color you set, unlike an SVG icon which would need its own fill color logic.
The checkmark scales proportionally with your size choice
Rather than using fixed pixel offsets for the checkmark's position and dimensions, every measurement is calculated as a percentage of the checkbox's own size: the left offset is 30% of size, the top offset is 12%, the tick's width is 28% of size, and its height is 50%. This is why dragging the size slider from 14px up to 40px keeps the checkmark looking correctly proportioned inside the box at every step, instead of the tick becoming tiny and off-center inside a large box or overflowing a small one, which is what would happen with hardcoded pixel values.
Accessibility is preserved because the underlying element doesn't change
A common but flawed approach to custom checkboxes is building a fake checkbox out of a <div> with a click handler, which breaks keyboard access (no Space-to-toggle), screen reader announcements, and form submission entirely unless you manually reimplement all of it with ARIA attributes and JavaScript. This generator never does that, it keeps a genuine <input type="checkbox"> in the markup and only restyles its visual appearance with CSS. That means Tab focus, Space-bar toggling, screen reader "checkbox, checked/unchecked" announcements, and native form submission all keep working exactly as they would with an unstyled checkbox.
A known limitation: no indeterminate state styling
Checkboxes support a third visual state beyond checked and unchecked, called indeterminate, commonly used for a "select all" checkbox when only some (not all) child items are selected. That state is set via JavaScript (element.indeterminate = true) rather than an HTML attribute, and it has its own :indeterminate CSS pseudo-class. This generator's output only styles :checked, so if your use case needs a dash/mixed-state visual, you'll need to add an :indeterminate rule to the copied CSS yourself, typically drawing a horizontal bar instead of the diagonal checkmark for that state.
Border radius as a design lever, not just decoration
The border-radius slider goes from a sharp square at 0 up to 20px, which for the default 22px checkbox size is large enough to round the box into a near-circle. A square or barely-rounded checkbox (0-4px) reads as more formal and matches most default OS checkbox conventions, while a fully rounded one is often paired with radio-button-adjacent UI, like tag-selection chips or filter pills, where a circular selected state feels more consistent with the rest of the interface.
Frequently Asked Questions
Why is appearance: none needed to style a checkbox?
Native checkboxes are rendered by the operating system's UI toolkit rather than the browser's normal CSS box model, which blocks most styling. appearance: none tells the browser to stop drawing the OS-native widget so properties like border, border-radius, and background can take effect.
Is the checkmark an image or icon font?
No, it's pure CSS. A pseudo-element is given a border on only its bottom and right sides, which forms an upside-down L shape, then that shape is rotated 45 degrees to become a checkmark tick. This needs no extra file requests and instantly matches whatever color you choose.
Will this custom checkbox still work with keyboard navigation and screen readers?
Yes. The generator only changes the checkbox's visual appearance with CSS, the underlying element is still a genuine input type="checkbox". Tab focus, Space-bar toggling, screen reader announcements, and form submission all continue to work exactly like a native unstyled checkbox.
Does the checkmark stay centered if I change the checkbox size?
Yes, the checkmark's position and dimensions are calculated as percentages of the checkbox's own size rather than fixed pixel values, so it stays correctly proportioned and centered whether you pick the smallest 14px size or the largest 40px size.
Does this tool support an indeterminate or "mixed" checkbox state?
Not out of the box. The generated CSS only styles the :checked state. If you need a dash-style indeterminate visual for something like a "select all" checkbox, you'll need to add your own :indeterminate CSS rule to the copied code.
Why does the output include both appearance: none and -webkit-appearance: none?
The unprefixed appearance property is now standard, but some older WebKit-based browsers required the -webkit- prefixed version to fully suppress the native checkbox rendering. Including both maximizes compatibility with no downside.