Search and highlight
Find a passage, show it, and be able to find it again months later.
The obvious way to build a find box is to walk the DOM looking for a string. It is wrong here for three reasons: it cannot see the pages that are not mounted, it matches the list numbers and page numbers the renderer computed rather than read, and what it produces is a DOM node — which cannot be stored, sent anywhere, or found again after a relayout.
So the search runs over the extracted text instead. A hit is a range of that text, a range is an address, and an address is a highlight. A passage retrieved from a vector database takes exactly the same path.
const search = await viewer.search();
const hits = search.find('quarterly revenue', { caseSensitive: false });
search.next(); // scrolls to the next hit
search.previous();
search.clear();Showing a stored passage
Selectors survive being written to a database and read back on another machine. Handing them to show scrolls to the passage and paints it.
const stored = await index.query('what is the notice period?');
search.show(stored.selectors);Why highlights do not move the text
Highlights are painted through the CSS Custom Highlight API, so nothing is inserted into the document. That matters because this viewer paginates by measuring what it rendered: a <mark> would change the width of the text it was marking and move the page break it sits near.
A highlight is registered state rather than an operation, so a passage nine hundred pages away is already painted by the time the reader scrolls to it — which is what makes "next" instant on a long document.