Scope: the Pandoc builder only. Zensical and Sphinx ship their own search. This is about build-pandoc, and about the hand-carried search.md that Pandoc-based sites using this repository each copy.
index-site builds a Pagefind index, but every site still carries its own search.md. Those pages are copies of each other, which turns a one-time improvement into a repeated chore.
They are already copies
Sampling repositories using PagefindUI:
| Repository |
|
CL-web-components, CL-Pandoc-filters, etd-workflow |
byte-identical bodies |
opensearch-machine |
stripped down — just element: "#search" |
feeds.library.caltech.edu |
genuinely customized (showSubResults, highlightParam, own query handling) |
The accessibility part
Pagefind 1.5.0 introduced a Component UI built on web components, with "greatly improved accessibility over the Default UI", keyboard navigation, and better RTL and locale handling.
This is not a version upgrade. index-site already pins 1.5.2, the current release, and the 1.5.0 notes are explicit:
The existing Default UI and Modular UI remain available and supported for now, so you can upgrade your sites to Pagefind v1.5.0 without migrating to the Component UI.
So nothing is broken and nothing is urgent. The improvement is opting into <pagefind-*> elements on the search page — the file every site copies.
Open questions, now answered
Does the Component UI support deep-linking? Yes. triggerSearch exists on the instance and is reachable without npm:
window.PagefindComponents.getInstanceManager()
.getInstance('default').triggerSearch(q);
Is the npm package needed? No. Pagefind emits pagefind-component-ui.css and pagefind-component-ui.js into /pagefind/; both are already in our built output. @pagefind/component-ui is only for bundler imports. index-site stays dependency-free.
Verified: the shared page can compute its own paths
A shared page cannot hardcode a deployment path, so it has to derive one. Both base-url and bundle-path must be set — setting only base-url fails outright with Could not load search bundle. Bundle path: /pagefind/, because auto-detection falls back to the site root rather than the prefix.
<link href="./pagefind/pagefind-component-ui.css" rel="stylesheet">
<pagefind-config id="pf-config"></pagefind-config>
<script>
// Classic inline script: runs during parsing. Module scripts are deferred,
// so this always executes before the custom elements are defined. Attributes
// are read once at connect, so setting them here is reliable, not a race.
var base = location.pathname.replace(/[^/]*$/, '');
var cfg = document.getElementById('pf-config');
cfg.setAttribute('base-url', base);
cfg.setAttribute('bundle-path', base + 'pagefind/');
</script>
<pagefind-input autofocus></pagefind-input>
<pagefind-results></pagefind-results>
<script src="./pagefind/pagefind-component-ui.js" type="module"></script>
<script type="module">
const q = new URLSearchParams(location.search).get('q');
if (q) {
window.PagefindComponents.getInstanceManager()
.getInstance('default').triggerSearch(q);
}
</script>
Tested against a real CL-web-components build served under a /CL-web-components/ prefix: results rendered with sub-results, ?q= populated the input, and links resolved to /CL-web-components/table-sortable.html — correct prefix, anchors included.
Where it goes
In build-pandoc, not index-site.
index-site must stay engine-agnostic — it indexes built HTML for any generator, and emitting a page would make it opinionated about theme and markup.
- The search page has to pass through the Pandoc template so it matches the rest of the site.
build-pandoc rendering pandoc/search.md gets that for free, with the project's own template override if it has one. A pre-baked search.html could not.
Proposed: build-pandoc gains a search-page input (default off) that renders the shared pandoc/search.md alongside the project's docs. Used with index-site, a site gets working accessible search with nothing in its own repository.
Option mapping, for anyone migrating a search page
| Default UI |
Component UI |
baseUrl |
<pagefind-config base-url> |
highlightParam |
<pagefind-config highlight-param> |
showSubResults: true |
now the default; opt out with hide-sub-results, tune max-sub-results |
showImages: true |
show-images on <pagefind-results> |
pageSize |
max-results — not equivalent, results lazy-load on scroll instead of paginating |
processResult |
<script type="text/pagefind-template"> inside <pagefind-results> |
resetStyles: false |
no equivalent; styling is CSS variables and parts |
triggerSearch(q) |
instance.triggerSearch(q) |
The Default UI also requires bolting on an aria-label for the search input by hand, since it does not provide one. The Component UI does, which is a concrete instance of the accessibility difference.
Suggested order
- CL-web-components — near-zero customization, proves the pattern, and it is the copy three other repos share
- Move the resulting page into this repository behind
build-pandoc's search-page input
- Adopt per site from there; sites with their own search page keep it
Context
Raised while restoring search in caltechlibrary/CL-web-components#46, where search.md and the committed index had been deleted but the generated search.html remained — so the live site served a search page whose assets 404'd.
index-sitebuilds a Pagefind index, but every site still carries its ownsearch.md. Those pages are copies of each other, which turns a one-time improvement into a repeated chore.They are already copies
Sampling repositories using
PagefindUI:CL-web-components,CL-Pandoc-filters,etd-workflowopensearch-machineelement: "#search"feeds.library.caltech.edushowSubResults,highlightParam, own query handling)The accessibility part
Pagefind 1.5.0 introduced a Component UI built on web components, with "greatly improved accessibility over the Default UI", keyboard navigation, and better RTL and locale handling.
This is not a version upgrade.
index-sitealready pins 1.5.2, the current release, and the 1.5.0 notes are explicit:So nothing is broken and nothing is urgent. The improvement is opting into
<pagefind-*>elements on the search page — the file every site copies.Open questions, now answered
Does the Component UI support deep-linking? Yes.
triggerSearchexists on the instance and is reachable without npm:Is the npm package needed? No. Pagefind emits
pagefind-component-ui.cssandpagefind-component-ui.jsinto/pagefind/; both are already in our built output.@pagefind/component-uiis only for bundler imports.index-sitestays dependency-free.Verified: the shared page can compute its own paths
A shared page cannot hardcode a deployment path, so it has to derive one. Both
base-urlandbundle-pathmust be set — setting onlybase-urlfails outright withCould not load search bundle. Bundle path: /pagefind/, because auto-detection falls back to the site root rather than the prefix.Tested against a real CL-web-components build served under a
/CL-web-components/prefix: results rendered with sub-results,?q=populated the input, and links resolved to/CL-web-components/table-sortable.html— correct prefix, anchors included.Where it goes
In
build-pandoc, notindex-site.index-sitemust stay engine-agnostic — it indexes built HTML for any generator, and emitting a page would make it opinionated about theme and markup.build-pandocrenderingpandoc/search.mdgets that for free, with the project's own template override if it has one. A pre-bakedsearch.htmlcould not.Proposed:
build-pandocgains asearch-pageinput (default off) that renders the sharedpandoc/search.mdalongside the project's docs. Used withindex-site, a site gets working accessible search with nothing in its own repository.Option mapping, for anyone migrating a search page
baseUrl<pagefind-config base-url>highlightParam<pagefind-config highlight-param>showSubResults: truehide-sub-results, tunemax-sub-resultsshowImages: trueshow-imageson<pagefind-results>pageSizemax-results— not equivalent, results lazy-load on scroll instead of paginatingprocessResult<script type="text/pagefind-template">inside<pagefind-results>resetStyles: falsetriggerSearch(q)instance.triggerSearch(q)The Default UI also requires bolting on an
aria-labelfor the search input by hand, since it does not provide one. The Component UI does, which is a concrete instance of the accessibility difference.Suggested order
build-pandoc'ssearch-pageinputContext
Raised while restoring search in caltechlibrary/CL-web-components#46, where
search.mdand the committed index had been deleted but the generatedsearch.htmlremained — so the live site served a search page whose assets 404'd.