@markitjs/react
v1.0.4
Published
React bindings for @markitjs/core text highlighting engine
Downloads
1
Maintainers
Readme
@markitjs/react
React bindings for the @markitjs/core text highlighting engine. Provides a useHighlight hook and a declarative Highlighter component.
Install
npm install @markitjs/react
# or
bun add @markitjs/react
# or
pnpm add @markitjs/react
# or (Yarn — include @markitjs/core explicitly)
yarn add @markitjs/react @markitjs/corePeer dependencies: React 18+ or 19+, and @markitjs/core (installed automatically by npm 7+, pnpm, and bun; with Yarn, add @markitjs/core explicitly: yarn add @markitjs/react @markitjs/core).
Quick Start
Hook
Next.js App Router: Add "use client" at the top of any file that uses the hook or <Highlighter>.
import { useHighlight } from '@markitjs/react';
function SearchResults({ query }: { query: string }) {
const ref = useHighlight(query, { caseSensitive: false });
return (
<div ref={ref}>
<p>Content to search and highlight.</p>
</div>
);
}Component
import { Highlighter } from '@markitjs/react';
function App() {
return (
<Highlighter term="react" accuracy="exactly">
<article>
<p>React is a JavaScript library for building user interfaces.</p>
</article>
</Highlighter>
);
}API
useHighlight(term, options?)
Returns a ref to attach to the container element.
const ref = useHighlight<HTMLDivElement>(term, {
// All @markitjs/core options, plus:
plugins: [], // MarkitPlugin[]
timing: 'effect', // 'effect' (default) | 'layout'
contentKey: value, // optional: re-run when content identity changes
});| Option | Type | Description |
| ------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| timing | 'effect' \| 'layout' | 'effect' runs after paint (SSR-safe). 'layout' runs before paint — use with the DOM renderer to avoid a flash of unhighlighted content. |
| plugins | MarkitPlugin[] | Plugins to register with the core instance. |
| contentKey | Key \| Key[] | When content is dynamic, pass value(s) that change with content so the effect re-runs and re-applies. |
All other options are passed through to @markitjs/core's mark() method. For dynamic content (e.g. state or props), pass contentKey so highlights re-apply when content changes and avoid garbled text. See Framework lifecycles for how the React highlight cycle works.
Highlighter
Declarative component that wraps children and highlights matching text.
<Highlighter
term="search" // string | string[]
as="div" // Container element tag (default: 'div')
className="my-class" // Container CSS class
style={{ padding: 16 }} // Container inline styles
contentKey={contentId} // optional: for dynamic content
caseSensitive={false} // Any @markitjs/core option
renderer="auto"
/>Safety
The bindings are designed to be safe across React's rendering model:
| Concern | How it's handled |
| ------------------------- | --------------------------------------------------------- |
| StrictMode | Cleanup runs before re-invocation; unmark is idempotent |
| Concurrent rendering | Effects only run on committed renders |
| Next.js SSR/hydration | useEffect doesn't run on the server or during hydration |
| Re-renders | Options are shallow-compared; no work if nothing changed |
| Unmount | destroy() is called in the effect cleanup |
Performance
- Term: A string term is already stable (same value = no extra work). When
termis an array, the hook compares by contents, not reference: passing a new array with the same items (e.g.[word1, word2]every render) will not re-run the effect. Optionally useuseMemofor the array if you want to avoid that internal comparison. - Options: Pass a stable options object (e.g.
useMemo(() => ({ ... }), [deps])or a constant) so the effect does not re-run when nothing actually changed. Options are shallow-compared; a new object reference every render may trigger re-runs even when values are the same.
Next.js Usage
The Highlighter component includes a 'use client' directive. Use it inside Client Components:
// app/search/results.tsx
'use client';
import { Highlighter } from '@markitjs/react';
export function Results({ query, html }: { query: string; html: string }) {
return (
<Highlighter term={query} renderer="auto">
<div dangerouslySetInnerHTML={{ __html: html }} />
</Highlighter>
);
}Server Components can render the content; the Highlighter applies highlights client-side after hydration.
Batched Rendering
For large content areas, enable batched rendering to keep the UI responsive:
const ref = useHighlight(query, {
batchSize: 500,
done: (count) => setMatchCount(count),
});CSS Highlight API Styling
When using the default auto renderer on supported browsers, add this CSS:
::highlight(markit-highlight) {
background-color: #fef08a;
color: inherit;
}License
MIT
