Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Search Highlight Text for React

Text with every match of a search marked as you type, each mark rising from an underline in reading order. For React with Base UI, when a page, an FAQ or a list should show where the query is.

Framework

Search Highlight Text marks every place a query appears in a text, the way find-in-page does, and draws the marks in as the query changes: each one is underlined at once, then filled from the underline up, one after another in reading order. Case and accents are ignored by default, so "resume" finds "Résumé".

Use it under a search field on a docs page, an FAQ, terms and conditions or a long list, where people need to see at a glance where their words are. For the same marks without the motion, use Highlight; to walk through the matches of a regular expression, Regex Text; to draw one phrase of your own copy, Highlight Text. The search is a plain string search, never a regular expression, and the marks are drawn by a CSS keyframe animation the install adds to your stylesheet, with no animation library. With reduced motion the marks are simply there.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import {
  SearchHighlightText,
} from "@/components/ui/search-highlight-text";
<SearchHighlightText query={query} text="Every component ships as source you own." />

Demos

Sensitivity

sensitivity is which differences between letters count, as in Intl.Collator: base, the default, ignores case and accents; accent ignores case only; case ignores accents only; variant matches exactly. The marks always hold the text as it's written.

Preview width

Color

highlightColor takes any CSS colour; theme variables mixed with transparent, such as color-mix(in oklab, var(--info) 30%, transparent), keep the text readable on it, light and dark. Style the marks themselves through data-slot="search-highlight-text-mark" or a [&_mark]: class.

Preview width

Accessibility

The text stays real text, read once by screen readers, with each match in a <mark>, which some of them announce as highlighted. The number of matches matters most to someone who can't see the marks: onMatchCountChange gives it to you whenever it changes, to show beside the search field in a polite status, as the first demo does ("2 matches"). In forced-colors mode the marks take the system's highlight colours. With reduced motion they're drawn at once.

FAQ

How is it different from Highlight?

Highlight marks the matches of one or several terms, case-sensitive by default, with no motion. Search Highlight Text is made for a search as it's typed: it ignores case and accents, draws each new set of marks in, and tells you how many there are.

Can someone type characters like a dot or a bracket?

Yes. The query is found as plain text, never compiled into a regular expression, so ., *, ( and \ are just themselves and nothing someone types can break it.

How are accents ignored?

Each character is split into its letter and its accents (Unicode's NFD form) and the accents dropped, in the text and in the query alike, so "cafe" finds "Café" and "Café" finds "cafe". The marks still hold the text exactly as written.

How do I show the number of matches?

Pass onMatchCountChange, such as a state setter: it's called with the count whenever it changes. Show it in an element with role="status" so screen readers hear it as the query changes, without moving focus.

What happens with a blank query?

Nothing is marked and the count is 0. A query of spaces counts as blank, and spaces around a query are ignored.

What colour are the marks?

Your theme's --warning at 40%, like a highlighter, light and dark; the install adds --warning to your theme if it doesn't have one. Pass highlightColor for any other.

What happens with reduced motion?

The marks don't rise: they're there in full as soon as the query changes.

API Reference

SearchHighlightText

<span> data-slot="search-highlight-text"

PropType
querystring

What to find in the text; blank marks nothing.

textstring

The text to search.

highlightColor?string

The marks' colour, any CSS colour; keep it light enough for the text to read on it.

Default
"color-mix(in oklab, var(--warning) 40%, transparent)"
onMatchCountChange?(count: number) → void

Called with the number of matches whenever it changes, to show it or announce it.

Parameters

count – number

Returns
void
sensitivity?Sensitivity

Which differences between letters count, as in Intl.Collator: base ignores case and accents (e finds É), accent ignores case only, case ignores accents only, variant matches exactly.

Default
"base"
render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

CSS variableType
--search-highlight-text-colorstring

The marks' colour.

All 97 text effects