Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/johnfactotum/foliate-js/llms.txt

Use this file to discover all available pages before exploring further.

search.js provides locale-aware full-text search over DOM documents. It can be used as a standalone module or via the higher-level view.search() method. The core implementation uses Intl.Collator and Intl.Segmenter to support diacritic-insensitive matching, case-insensitive matching, and whole-word search. Matches can span multiple adjacent text nodes. The search is inherently incremental — you should consume results lazily rather than waiting for the entire book to be scanned.

Import

import { searchMatcher } from './foliate-js/search.js'
import { textWalker } from './foliate-js/text-walker.js'

searchMatcher(textWalker, options)

Creates a reusable matcher generator function that searches a single document at a time.
textWalker
function
required
The textWalker function from text-walker.js. Passed in as a dependency so the module remains loosely coupled.
options.defaultLocale
string
BCP 47 locale tag used when the document has no lang attribute (e.g. 'en', 'ja'). Falls back to 'en' if not set.
options.matchCase
boolean
default:"false"
When true, the search is case-sensitive.
options.matchDiacritics
boolean
default:"false"
When true, diacritics are treated as significant (e.g. ée).
options.matchWholeWords
boolean
default:"false"
When true, uses Intl.Segmenter with granularity: 'word' so that only complete word matches are returned.
options.acceptNode
function
An optional node filter passed to textWalker to restrict which text nodes are searched. Same signature as a TreeWalker filter.
Returns a matcher generator function.
const matcher = searchMatcher(textWalker, {
    defaultLocale: 'en',
    matchCase: false,
    matchDiacritics: false,
    matchWholeWords: false,
})

The returned matcher(doc, query)

The matcher returned by searchMatcher is a generator function. Call it with a section document and a query string to iterate over all matches within that document.
doc
Document
required
The section Document to search. Its lang attribute (on <html> or <body>) is used to select the locale for Intl.Collator and Intl.Segmenter.
query
string
required
The search string.
Yields objects with the following shape for each match:
range
Range
A DOM Range spanning the matched text in the document.
excerpt
object
Context strings surrounding the match.
const matcher = searchMatcher(textWalker, { defaultLocale: 'en' })

for (const { range, excerpt } of matcher(sectionDoc, 'whale')) {
    console.log(excerpt.pre + '[' + excerpt.match + ']' + excerpt.post)
    // highlight range in the document...
}

Sensitivity mapping

The four option flags map to Intl.Collator sensitivity as follows:
matchDiacriticsmatchCasesensitivity
falsefalse'base' — ignore diacritics and case
truefalse'accent' — distinguish diacritics, ignore case
falsetrue'case' — ignore diacritics, distinguish case
truetrue'variant' — exact match
When Intl.Segmenter is unavailable, or when granularity is 'grapheme' and sensitivity is 'variant' or 'accent', the implementation falls back to a simple String.prototype.indexOf-based search.

Incremental usage

Searching an entire book section-by-section is slow. Load results one section at a time and yield control between sections:
const matcher = searchMatcher(textWalker, { defaultLocale: 'en' })

async function* searchBook(book, query) {
    for (const section of book.sections) {
        const doc = await section.createDocument()
        for (const result of matcher(doc, query)) {
            yield result
        }
    }
}

for await (const { range, excerpt } of searchBook(book, 'Moby Dick')) {
    console.log(excerpt.match)
}
view.search() does this automatically and draws search highlights via the overlayer. Use searchMatcher directly when you need the raw ranges or excerpts without the rendering layer.

Build docs developers (and LLMs) love