v158 · css · custom highlight api

CSS Custom Highlight Universal Selector ::highlight(*)

The Custom Highlight API styles arbitrary text ranges with no extra DOM — but every registered highlight needed its own ::highlight(name) rule, so shared styling meant repeating the same declarations for each name. ::highlight(*) matches the highlight pseudo-elements of all registered highlights, and its * argument contributes zero specificity: it is a base layer that any named rule overrides through the cascade, whatever the source order.

concepts

  1. Universal base style

    Register three real Highlight objects over live text — that part ships everywhere Chrome 105+. Then inject a ::highlight(*) rule through a constructed stylesheet and watch the exact parse verdict: one rule styles every highlight where supported, with the honest per-name repetition fallback shown working beside it.

  2. Zero-specificity cascade

    The subtle half of the contract. Flip the source order of a universal rule and a named rule and read the painted colours back with getComputedStyle(el, "::highlight(name)") — the named rule must win even when the universal rule comes last, because * adds nothing to specificity.

  3. Multi-category annotator

    A working find-in-page tool: search the article, every match becomes a search-match highlight and the active one a higher-priority search-current highlight with keyboard next/previous. ::highlight(*) is the shared chrome every category inherits — one rule instead of one per category.

why it shipped

Authors building spell-checkers, collaborative cursors, syntax colouring, or search highlighting register many named highlights whose styles share a base (a contrast-safe background, an underline, a transition). Without a universal form, those declarations are duplicated per name and drift apart. The CSSWG resolved to allow ::highlight(*) with zero specificity from the argument so it layers cleanly under existing named rules — the same shape as * in selectors generally. Chrome 158 implements it behind CSSCustomHighlightUniversalSelector on the way to stable.

the API

/* base layer for EVERY registered highlight — zero specificity */
::highlight(*) {
  background-color: oklch(95% 0.05 95);
  text-decoration: underline dotted;
}

/* any named rule overrides the base, regardless of order */
::highlight(spelling-error) { text-decoration: underline wavy red; }

Only highlight-safe properties apply (color, background-color, text-decoration and friends) — that part is unchanged from the shipped Custom Highlight API.

references