Lazy-loaded content must be findable by in-page search
Aliases: find in page vs lazy load · ⌘F miss · unmaterialised text
What it is
In-page search (find in page, ⌘F, a widget’s own filter) assumes that words on the page can be found. If lazy loading removes off-viewport text, list rows or collapsed panels from the DOM — or has not fetched them at all — search reports “none” while the content is waiting below to start existing when scrolled. Lazy loading may cut first-screen cost. It must not quietly cut findability: content not yet painted must still be hittable, or must be fetched and scrolled to when a hit would have landed there.
Why it happens
Search walks strings already in the document, not visual visibility. Common lazy-load implementations turn “not near the viewport” into “the node does not exist”: a virtual list mounts a handful of rows and the rest is height accounting; a disclosure’s body is inserted only on open; image alt is still on the server. The user looks for a word, the engine scans existing nodes, zero hits, and the model becomes “the page does not contain this word”. The model is wrong: the word lives in a stretch not yet materialised. Findability requires materialisation and search to share an index: either unpainted text still exists in a searchable form (hidden, not deleted; or a text index), or a hit on an unloaded stretch loads then locates, rather than returning none.
Virtualisation steps on this leaf especially. It renders a window for scroll feel; rows outside the window vanish from the accessibility tree and from find-in-page. A scrolling user can “feel” that content is still there. A searching user has no such feeling, only a false negative.
Where it stops holding
Lazy images usually leave body text in place, so find-in-page for words is unaffected; if the only key information is in the image and there is no searchable alternative, the miss is a content-shape problem, not a trigger line. Server-paginated or infinite lists whose next page has not been requested are genuinely not on this page; not finding them in-page is correct — people should be told the scope is “what is loaded” and offered a corpus search, not a pretence that the whole corpus is in the DOM. Encrypted or still-locked sections are not readable; search must not unseal them early. Native find-in-page is already weak across documents, canvas and Shadow DOM; in-product find has to cover that, and must not assume ⌘F will pierce a virtual list.
Applying it
- Keep a searchable text for virtual lists and lazy disclosures (hidden nodes or a separate index). On a hit, scroll there and load the real content.
- If the product’s own search box only scans rendered nodes, lazy loading has become silent word-drop. Scan the logical document.
- Label infinite scroll as “searching the loaded portion” and give an entry to search all, so a false negative is not read as absence.
- How to check: place a unique word in a stretch that only loads after scrolling to the middle, return to the top, and ⌘F or use in-page find. If it cannot be found, or is found but cannot locate an unrendered row, findability has been eaten by lazy loading.