Search

How does the Search Work?

The search block provides a full-site search experience that lets visitors find any published page from a single, dedicated search page. The header includes a search icon (togglable by authors) that navigates users to this page.

Indexing is handled by the EDS platform via helix-query.yaml. It defines a pages index that crawls all published pages (excluding .json files) and extracts 7 properties — title, description, image, tags, content, lastModified, robots — into /query-index.json.

Querying is entirely client-side:

  1. On block load, the query index JSON is fetched and cached in a Map. The fetch is deferred via requestIdleCallback (1500ms timeout) or triggered on first input focus — whichever comes first — to avoid impacting LCP.

  2. Filter ("Search in"): A dropdown that narrows which indexed fields are searched — visitors can restrict matches to Title, Description, Content, Tags, or Path instead of the default All Fields. Under the hood, filterPages() performs case-insensitive substring matching (String.includes()) against the selected field(s), with the Title option checking three sources (actual title, navTitle, and a path-derived title). Changing the filter re-runs the search instantly with no debounce, and the selection persists in the URL as ?filter=.

  3. Sort ("Sort by"): A dropdown that reorders the filtered results by Most Relevant (default), Least Relevant, Title A–Z, or Title Z–A. Relevance is a cumulative score computed per result — exact title matches score highest (100pts), followed by tags (25pts), description (15pts + 3/occurrence), and body content (1/occurrence) — so well-authored pages with strong metadata naturally rank at the top. Title sorting uses localeCompare() for proper alphabetical ordering. Like filter, changing the sort is instant and persists as ?sort= in the URL.

  4. Results are rendered via DocumentFragment for batched DOM writes, with replaceChildren() to avoid flicker. An LRU cache (500 entries) optimizes repeated stripHTML() calls. Input is debounced at 300ms.

  5. All user-generated content is run through escapeHTML() before rendering, and result links are validated to start with / to prevent XSS.

  6. Search results are plugged into Pagination engine automatically (utilizes Pagination block functionality).

File footprint: The entire search feature is self-contained in blocks/search/, plus the shared pagination engine in blocks/pagination/pagination.js. No external search service or server-side API is involved.

default