zudo-text

検索したい単語を入力

いつでも検索バーを開ける

@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

MethodDescription
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

  1. TreeWalker — collects all text nodes within the container

  2. Case-insensitive search — finds all occurrences of the query in each text node

  3. DOM splitting — splits text nodes at match boundaries and wraps matched text in <mark> elements

  4. Active match — adds an extra CSS class to the current match and scrolls it into view via scrollIntoView({ block: "center" })

  5. Cleanup — on stop(), replaces each <mark> with a text node and calls normalize() 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.