Styling checkboxes with the CSS checkmark pseudo-element

Bold text reading Style the Tick beside an isometric white checkbox with a blue gradient tick and small floating controls.
input[type="checkbox"] {
  appearance: base;
}

input[type="checkbox"]::checkmark {
  stroke: var(--wp--preset--color--vivid-red);
}

With ::checkmark you can style the tick of a native checkbox without touching its markup or hiding the real input behind a fake box. The pseudo-element comes out of the CSS Form Control Styling Level 1 work, and it also applies to the checked indicator of radios and the selected option inside a customizable select, which I covered when I wrote about the Customizable Select API. Chromium supports it. Safari and Firefox don’t yet, as Andy Bell notes in the MDN piece the roundup links to, and you have to plan around that gap.

This started from the CSS-Tricks roundup What’s !important #12, which collects ::checkmark, anchor associations through data attributes, new shape styles and more. Most of it is good reading, but only one item leaves a WordPress developer with an actual decision about what to ship, so that’s the one I’m writing about.

What the checkmark pseudo-element styles

I care about this because of who owns the markup. On a WooCommerce checkout, the terms checkbox and the payment method radios are rendered by plugin templates. You can override those templates, but overrides rot: WooCommerce changes its markup, your copy goes stale, and the checkout breaks on the next update without telling anyone. A pseudo-element that styles the built-in indicator needs none of that. The markup stays plugin-owned and you stay in CSS.

It helps with accessibility too. Fake checkboxes built with appearance: none and a hand-drawn tick are where focus states usually fall apart. ::checkmark keeps the native control in place, so focus, the checked state and forced-colors mode keep working, because the browser still owns them.

Ship the fallback first

This is the order I use:

  1. Style the native checkbox for everyone: accent-color for the tint, a real :focus-visible ring, sane sizing.
  2. Put anything that depends on ::checkmark inside @supports selector(input[type="checkbox"]::checkmark).
  3. Test the fallback in Safari, because that’s what Safari users will see.
input[type="checkbox"] {
  accent-color: #cf2e2e;
}

@supports selector(input[type="checkbox"]::checkmark) {
  input[type="checkbox"] {
    appearance: base;
  }

  input[type="checkbox"]::checkmark {
    stroke: #cf2e2e;
    stroke-width: 2;
  }
}

Gating both properties on the same query is deliberate. appearance: base is new as well, and a browser that supports one but not the other would render a checkbox with no native paint. With the gate, the worst case is the platform tick rather than a blank box.

Safari users get the fallback, and Safari is also the awkward browser to test. The roundup calls it the second most popular browser while noting it only runs on Apple hardware, which is why the linked Frontend Masters piece on testing Safari on a budget exists. If you don’t have a Mac nearby, that piece lists the options, from rented cloud Macs to a few cheaper tricks of mixed fidelity.

Where it fits in WordPress and WooCommerce

Two scoping rules. Keep these selectors off wp-admin: the admin checkbox styles live in forms.css and are tuned for density, and spraying appearance: base over admin inputs will wreck screen options and settings screens. And prefix the front-end rules with their form context, something like .woocommerce-checkout input[type="checkbox"], so they can’t leak into plugin modals that expect the native look. I’m not sure how this interacts inside the site editor’s own settings panels; staying scoped avoids the question.

The pattern pays off on stores with heavy Chromium traffic and costs nothing anywhere else, which fits my bar for shipping a progressive enhancement. If you want your checkout or theme forms restyled this way, with the native controls intact and no template overrides, that’s work I do regularly, so get in touch.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.

Leave a Comment