Highlight the same word in three different ways. At the same time.
A TypeScript-first library for substring highlighting with first-class multi-state per-match styling. Every match gets a base style. Specific matches — by index, range, list, or your own predicate — get layered styles on top. Bring precomputed ranges when your own matcher already found them. ~2.7 KB brotlied. Two micro-dependencies. SSR-safe. React, React Native, or no framework at all.
// Every "time" gets hl-base. Then layer states on top.
import { Highlight } from 'one-more-highlight';
<Highlight
text="time time time time time"
searchWords={['time']}
highlightClassName="hl-base"
states={[
{ name: 'active', index: 2, className: 'hl-active' },
{ name: 'preview', range: [0, 1], className: 'hl-preview' },
{ name: 'bookmarked', indices: [3, 4], className: 'hl-bookmark' },
]}
/>
TypeScript-first
Discriminated union narrows on the selector field — index,
range, or indices.
Tiny
~2.7 KB brotlied for the core (ESM); ~3.2 KB for the CDN bundle.
Two micro-deps (clsx, escape-string-regexp),
both MIT, ~400 B combined. /css, /vanilla,
/native, /a11y and /navigation
are opt-in — you only pay for what you import.
React, native, or none
<Highlight> on the web, <HighlightText> from
/native, or /vanilla with no framework at all.
The selectors stay the same.
SSR-safe
No window, no Date.now, no Math.random.
Hydration matches.
Get started
$ pnpm add one-more-highlight
Peer dependency: react ≥ 18. react-native ≥ 0.70
is optional and used only by the /native entry point.