My Learning Curve

Feed / Piccalilli - CSS topic archive

Navigating the age-old problem of checkmarks in UI with progressive enhancement

Thursday, May 28, 2026

The ::checkmark pseudo-element was introduced in CSS Form Control Styling Module Level 1 and it’s a powerful CSS feature to say the least. I even wrote about it as an almanac entry for CSS-Tricks in 2025 to share what this pseudo-element can do.

The CSS ::checkmark pseudo-element is used to style the checked state of input elements with checkers including the dropdown.

This means that ::checkmark , as simple, powerful, and useful as it is, is still very limited, and that’s a problem. So, do we rely on the traditional solutions we used to use in the past to style checkmarks? Are they better? In this article, we will be exploring how the problem of customised checkmarks was solved in the past and compare those solutions with the modern ::checkmark solution, providing recommendations as we go.

How we’ve traditionally approached checkmarks in menus

To create and style a traditional checkmark similar to the ones you see in elements under dropdown:


The HTML is pretty concise when compared to the previous solution, right? It’s amazing what happens when we use semantic elements. This way, the browser handles everything for us. Accessibility, keyboard navigation, and every standard behavior we expect from our dropdown, without any hassle. Just define a dropdown using dropdown and you’re set for styling your checkmarks using ::checkmark and changing the default check using content!

See the Pen ::checkmark demo (no JS required!) by Andy Bell (@piccalilli) on CodePen.

No JS required!

A win for progressive enhancement because it essentially accounts for all the major issues associated with creating a custom dropdown and having a custom checkmark style. This solution, even when JS fails, will still work out fine.

This approach is clearly better than the previous approach, but there are a few issues with this that I think we should touch on.

The problem with ::checkmark

It’s amazing what this pseudo-element can do and what it is intended to do. It’s also amazing the amount of code it saves. Not only do I need to write less code to achieve the same result (efficiency), but the browser also handles the default behavior I expect when I click outside the dropdown (the dropdown closes automatically).

There are a few issues with ::checkmark that I want to address though.

  1. There’s limited browser support. At the time of writing, ::checkmark is only supported in 3 major browsers and not across the board. That would suck for a user having to experience a feature in one browser and be absent on the next.
  2. Lacking full feature support: According to the documentation, ::checkmark is supposed to work for checkboxes, radios, and options. Guess what? In browsers that currently support this, only the options from element, we get the correct announcements from assistive technology too.

    My only plea is that for our checkmarks to be styled correctly, major browser vendors may need to provide full support for this feature as soon as possible, so we can style our own custom checkmarks without having to rely on JS at all, ever again.

Read original article ↗