Highlight the same word in three different ways. At the same time.

A TypeScript-first React and React Native library for substring highlighting with first-class multi-state per-match styling. Every match gets a base style. Specific matches — by index, range, or list — get layered styles on top. ~2.3 KB brotlied. Two micro-dependencies. SSR-safe.

Rendered output
time time time time time
#0base + preview #1base + preview #2base + active #3base + bookmarked #4base + bookmarked
Highlight.tsx
// 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.3 KB brotlied (ESM). Two micro-deps (clsx, escape-string-regexp), both MIT, ~400 B combined.

Web + native

Use <Highlight> on the web or <HighlightText> from /native. 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.