@takazudo/find-in-page
DOM-based text search for the markdown preview pane. Highlights matching text with <mark> elements and provides navigation between matches.
Main Exports
import { createFindInPage } from "@takazudo/find-in-page";
import type { FindInPage, FindResult } from "@takazudo/find-in-page";API
createFindInPage()
Creates a find-in-page instance that manages search state and DOM highlighting.
function createFindInPage(): FindInPage;
interface FindInPage {
find(container: HTMLElement, query: string): FindResult;
next(): FindResult;
prev(): FindResult;
stop(): void;
}
interface FindResult {
matches: number;
activeMatchOrdinal: number; // 1-based
}Usage
import { createFindInPage } from "@takazudo/find-in-page";
const finder = createFindInPage();
// Search within a container element
const container = document.getElementById("preview");
const result = finder.find(container, "search term");
console.log(`${result.activeMatchOrdinal} of ${result.matches}`);
// Navigate between matches
finder.next(); // move to next match
finder.prev(); // move to previous match
// Clear all highlights
finder.stop();Methods
| Method | Description |
|---|---|
find(container, query) | Searches the container for the query string. Clears previous highlights, wraps matches in <mark> elements, and activates the first match. |
next() | Moves to the next match (wraps around). Returns updated FindResult. |
prev() | Moves to the previous match (wraps around). Returns updated FindResult. |
stop() | Removes all <mark> elements and normalizes text nodes back to their original state. |
How It Works
TreeWalker — collects all text nodes within the container
Case-insensitive search — finds all occurrences of the query in each text node
DOM splitting — splits text nodes at match boundaries and wraps matched text in
<mark>elementsActive match — adds an extra CSS class to the current match and scrolls it into view via
scrollIntoView({ block: "center" })Cleanup — on
stop(), replaces each<mark>with a text node and callsnormalize()on each parent to merge adjacent text nodes
CSS Classes
The package includes a stylesheet for highlight styling:
import "@takazudo/find-in-page/styles.css";.find-match {
background-color: rgba(255, 200, 0, 0.4);
border-radius: 2px;
}
.find-match-active {
background-color: rgba(255, 150, 0, 0.7);
border-radius: 2px;
outline: 2px solid rgba(255, 150, 0, 0.9);
}The <mark> elements also have data-find-match and data-find-active attributes for custom styling or querying.
Limitation
Only matches text within a single text node. Cross-element matching (e.g., "Hello world" spanning <strong>Hello</strong> world) is not supported. This is a deliberate trade-off for simplicity and performance.
Dependencies
None (standalone DOM package). Uses jsdom for testing.