useHighlight

Marks text matches, such as search results, with the browser's CSS Custom Highlight API. The hook finds each match as a Range and adds it to a Highlight in CSS.highlights; your CSS paints it with ::highlight(name). No <mark> elements are added, so the DOM, the selection and focus stay as they are.

Put ref on the element to search and pass query. The hook searches again when text or elements under ref change. Matching ignores letter case unless caseSensitive is set, and the query is plain text, not a pattern. A list matches any of its terms.

const found = useHighlight({ name: 'search', query })

<article ref={found.ref}>{children}</article>
<output>{found.matches.length} results</output>
::highlight(search) {
	background-color: var(--todae-color-status-warning-bg);
	color: var(--todae-color-fg-default);
}
No matches

Todae ships design tokens in the DTCG format. A company adds its own tokens on top, and every component reads them, so a token change reaches buttons, fields and dialogs at once.

matches holds a live Range per match, in document order. Text hidden by CSS is still matched. A match must sit inside one text node, so a word split by markup, such as fo<b>o</b>, is not found.

To mark the current result, pass it to a second hook as ranges under another name, with a higher priority so it paints on top. The demo above does this. Give each hook its own name; to style several the same way, list them: ::highlight(a), ::highlight(b). type sets spelling-error or grammar-error for spelling and grammar marks.

The hook does not announce anything. Show the count in an <output> or other live region when a screen reader user needs it.

When to use

When: Marking text without changing the DOM: find in page, search results in a list or document, matched letters in a filter.

When not: Highlighting that must be in the accessibility tree → a real <mark> element. A single selected item in a list → aria-selected and a style, as OptionList does.

Props

useHighlight props
NameTypeRequiredDefaultDescription
namestringyes—Name to style with ::highlight(name). Give each hook its own name.
querystring | readonly string[]no—Text to find inside the element on ref. A list matches any of its terms; empty strings are skipped.
caseSensitivebooleannofalseMatch letter case exactly.
rangesreadonly AbstractRange[]no—More ranges to paint, such as the current match. They need no ref and are not added to matches.
prioritynumberno0Which highlight paints on top where two overlap. Higher wins.
type'highlight' | 'spelling-error' | 'grammar-error'no'highlight'Highlight type, for spelling and grammar marks.