Add a progressively enhanced site-search dialog
Update 2026-09-03 — search index schema version 3 records the canonical
/development/**route family. The version change invalidates cached indexes containing retired/spdtf/**links; development then rebuilds the complete generated-page corpus from the resolved Astro routes.The canonical search page now uses the unreserved shared documentation shell, including its standard no-breadcrumb title spacing. Its query is presented without a separate promotional introduction or visible helper paragraph; an assistive-technology label continues to name the field.
Update 2026-09-04 — the full search page uses the knowledge-base sections as its primary tabs: All, Ontology resources, Decisions, Programme, Governance, Modelling, Development, Working groups and Resources. Each tab supplies its own relevant filter set; sections without an orthogonal refinement do not repeat their destination as a page-type filter, while ontology resources and decisions retain their specialist filters. The shared filters use the page shell’s existing collapsible left rail, which sits outside the max-width content track. The result register therefore retains the full content width and can use three columns on wide screens. Moving the filter panel into that rail preserves its established typography and disclosure styling; the rail label supplies the heading, avoiding a duplicated
Filter resultstitle inside it. The result count shares the tab row; when no applied-filter chips exist, their status strip, divider and reserved vertical space are omitted. The filter rail retains the shared standard width; its duplicate horizontal inset is removed so canonical labels and counts can use the available internal measure. Filter options use a clearer vertical rhythm, with each checkbox aligned to the first line of its label.Corpus review on 4 September also retired Page type from current facet selection, ranking and card labels. Its inferred route-family values duplicated Section or Collection and did not form a consistently authored taxonomy. Schema-3 page-type metadata remains accepted so existing templates and cached indexes continue to load; existing
pagetypeURLs retain their exact filter as a removable legacy chip.
Context and problem statement
The global header currently exposes search as an icon link to /search. The search
page is useful for deliberate research because it supports summaries, metadata and
destination filtering, but opening a separate page is unnecessarily slow when a reader
only wants to jump to a known subject or route.
The site needs a fast search layer without creating a second search platform, hiding
authority and maturity information, weakening keyboard access, or turning the header
into an animated application launcher. The existing /search route must remain the
canonical rich-results view and the fallback when client-side enhancement is unavailable.
Fable 5.1 MAX produced a read-only interaction and visual specification on 2 September 2026. Fable was asked to work within the accepted OPDA design system and had no authority to change routes, programme content, publication or deployment.
Decision drivers
- Let readers jump directly to a known page without leaving their current context.
- Preserve one index, one ranking function and one vocabulary for search results.
- Keep
/searchavailable as a normal link, form target and shareable rich-results page. - Provide complete keyboard, screen-reader, reduced-motion and forced-colour behaviour.
- Use the existing semantic tokens, restrained geometry and ink-and-amber visual language.
- Avoid remote search services, query tracking, search-history persistence and AI answers.
- Keep the implementation compatible with Astro client navigation.
Considered options
Keep the search page only
This is the simplest implementation and remains the fallback, but it makes quick navigation slower and removes the reader from the page they are using.
Replace /search with a client-only command palette
Rejected. It would make search dependent on JavaScript, reduce the value of shareable filtered URLs and encourage application-style commands that are outside the site’s documentation purpose.
Add a progressively enhanced native dialog
Chosen. The existing link still reaches /search; client-side code intercepts it only
after the dialog controller is ready. The dialog uses the same local search module and
offers direct navigation while preserving the full search page for deeper work.
Decision outcome
The header search link will progressively enhance into a native <dialog> whose
accessible name is Search documentation. Its deliberately compact visible shell contains:
- a real GET search form whose action is
/searchand whose field is namedq; - a listbox of ranked destinations; and
- a link to open the full search page with the current query.
The result count and loading state remain available through a visually hidden live region. The quick-search surface has no visible heading, help paragraph, keyboard legend or close icon; the input itself provides the visual purpose of the surface.
The controller will dynamically import the existing site-search.mjs and its IA data on
first open, with an optional warm-up on trigger hover or focus. There will be no second
index or ranking implementation. A query typed during loading will run when the module
resolves. If loading fails, the dialog will say Search couldn't load. and retain the
working link to /search.
The field keeps an accessible label and uses the concise placeholder Search documentation.
Empty-state copy reuses the wording already owned by the search page.
Each compact result will show, in order:
- destination and facet; and
- page title.
Summaries, destination filters, work area, authority and maturity remain on /search.
This keeps the overlay a quick-jump layer and reserves the richer evidence context for the
full search page.
Interaction contract
- The existing search icon remains an ordinary
/searchanchor and keeps its accessible name. Command+K,Control+Kand/outside editable controls open the dialog. On/search, the shortcut focuses the page search field instead.- Up and Down Arrow move the active result while DOM focus remains in the search field
through
aria-activedescendant. - Enter follows the active result; Command+Enter or Control+Enter opens it in a new tab.
- Enter without an active result submits the real form to
/search?q=…. - Escape and a backdrop action close the dialog and return focus to its trigger.
- Tab order includes the input and the full-search link; result options are controlled from the input rather than becoming a long sequence of tab stops.
- The dialog closes before Astro swaps the current page and rebinds once on
astro:page-load.
Visual contract
On desktop, the panel will be no wider than the shared 64rem search-dialog token, use the standard dialog elevation, strong border and small design-system radius, and carry the four-pixel yellow structural rule used elsewhere by the site. The backdrop uses deep ink at 60 percent opacity. The result region scrolls independently and active results combine a selected surface with a three-pixel inline rule, so selection never relies on colour alone.
At the 40rem breakpoint the dialog retains a small viewport inset so the backdrop remains an obvious pointer-dismissal target. The full-search link remains, and input text stays at least the base size to avoid mobile focus zoom.
Motion is limited to a short opacity and vertical entrance using shared duration and easing tokens. There is no scale, blur, bounce, glass surface or ambient animation. Reduced-motion users receive effectively immediate state changes.
The light and dark themes will use semantic surface, border, text, action and focus tokens. Forced-colour mode will add an explicit active-option outline.
Implementation boundary
The proposed implementation is limited to:
- a shared
SiteSearchDialog.astrocomponent; - the existing
Header.astrosearch trigger; - a dedicated design-system search-dialog stylesheet, because the current component stylesheet is at its file-size limit;
- the design-system stylesheet manifest;
- focused search-dialog unit and browser coverage; and
- the search section of
DESIGN.md.
src/lib/site-search.mjs, src/lib/site-ia.mjs and the /search information architecture
remain authoritative and should not be forked.
Consequences
Positive
- Common searches take fewer steps while the full search page remains intact.
- The overlay and rich view cannot disagree about ranking because they share one module.
- The search trigger retains a useful destination before enhancement and on failure.
- Native dialog semantics provide focus containment, Escape handling and inert page content with less custom code.
- The compact result presentation is quicker to scan than the rich search page.
Negative
- The header gains client-side state and Astro navigation lifecycle handling.
- Native dialog behaviour still needs cross-browser and mobile-keyboard verification.
- Compact results cannot carry the full summaries and controls available on
/search.
Neutral
- The existing search route and public URLs do not change.
- Search remains local and does not collect or transmit query history.
- This decision authorises repository implementation only, not publication or deployment.
Confirmation plan
Implementation should confirm:
- ordinary link and GET-form fallbacks;
- first-open loading and import-failure recovery;
- keyboard opening, result navigation, activation, closure and focus return;
- accessible names, live status and listbox state;
- mouse, touch, small-screen and virtual-keyboard behaviour;
- light, dark, reduced-motion and forced-colour presentations;
- operation across Astro client navigation; and
- identical ranking between the dialog and
/search.
Implementation status
Implemented 3 September 2026. The shared dialog, header trigger, dedicated
design-system module, manifest entry and focused contract coverage are in place. The
controller imports site-search.mjs and site-ia.mjs only when needed, so the original
index and ranking remain authoritative. The data-backed Astro build completed successfully.
Focused verification covers the ordinary /search trigger destination, native dialog
semantics, GET fallback, shared dynamic imports, keyboard shortcut routing, active-result
state, Astro lifecycle rebinding, semantic tokens, mobile/reduced-motion/forced-colour
rules and the versioned stylesheet manifest. Manual visual and assistive-technology checks
remain appropriate release follow-up, particularly for mobile virtual keyboards.
Updated 3 September 2026. The quick-search surface was widened to 64rem and reduced to its essential controls. The visible heading, close icon, instructional copy, keyboard legend and verbose result metadata were removed. The accessible dialog name and live status remain, while Escape and backdrop dismissal continue to return focus to the trigger.
The canonical /search page was also revised after a second read-only Fable 5.1 MAX
review. It now separates the visible result count from its debounced live announcement,
debounces shareable URL updates, uses native reset behaviour, gives results a consistent
heading structure, and provides clearer empty-state recovery. Its presentation lives in a
dedicated design-system module; the shared index and ranking function remain unchanged.
The same review exposed that the initial revision had retained the old row-list
composition and allowed article-level h2 rules to override result titles. The results
are now full-track square register cards built on the shared card primitive, with a
bounded search toolbar and bottom-aligned authority facts. Indexing, ranking, URL state,
result semantics, announcements and recovery behaviour are unchanged.
Updated 3 September 2026 (corpus-wide search). A stakeholder review rejected the five generic dropdowns (area, collection, content type, context, status) that the first full-corpus revision had added. The search layer was redesigned around one shared data model and now covers every emitted page, including each generated ontology resource.
src/lib/site-search-model.mjsis the single facet vocabulary: result type (ontology resource, decision record, working group, page), collection (Property Pack ontology candidate, PDTF schema-derived ontology draft, PDTF JSON Schema input, ADR register, ODR register), working group or domain (the six bounded contexts plus the Common boundary, DBT Smart Data and Interoperability), ontology resource kind (class, object property, datatype property, SHACL node shape, SKOS concept scheme, SKOS concept, semantic context, source data point), and decision status. Every value is emitted by a current template; no facet implies an SPDTF ontology beyond the Property Pack candidate and the PDTF-derived draft.- Page type is retained only as schema-3 compatibility metadata. The generated-corpus
audit found that its route-derived values duplicated Section or Collection, while its
few cross-section values combined unrelated purposes. It is therefore not exposed as
a facet, included in ranking or shown on cards; existing
opda:search-page-typetags and cached records still normalise safely during migration. ExistingpagetypeURLs preserve their exact filter through a removable legacy chip. - Generated templates declare their facets through Layout’s
searchprop, emitted asopda:search-*meta tags; the build integration reads those tags from every emitted page, applies route defaults from the model to everything else, merges the editorial aliases by URL, and writes a schema-version-3 index. Page authority and maturity are not duplicated into the index; cards read them from the IA status registry. /searchis a native GET form whose section tabs and facet checkboxes form a shareable URL state. The tabs are the six canonical horizontal-navigation sections plus All, Ontology resources and Decisions; the six section tabs align with the global destination registry. Each tab exposes only meaningful facet groups, carries live counts computed with its own selection excluded, disables empty options, and becomes removable chips once applied. Filters use the same left-rail shell, collapse control and responsive drawer as section navigation; the rail remains outside the max-width content track. Results use three columns on wide screens and share one card anatomy with a variant rule and facts per result type. Heading, controls and cards useminmax(0, …)tracks aligned to the header content edge.- The quick-search dialog now ranks through the same generated index via
searchSiteand shows each record’s shared eyebrow, so both surfaces cannot disagree about ranking or vocabulary. The dialog shows the first twelve matches and links to the full count on/search. - Development serves the same corpus without a build. The integration enumerates every
page route through Astro’s resolved-routes hook and each page’s own
getStaticPaths, renders the routes through the running dev server, runs the identical HTML extractor, and serves the result at/data/site-search-index.json. The first request waits for that crawl; later dev sessions serve the cached index from Astro’s cache directory immediately while it refreshes. Verbatim HTML copied frompublic/(third-party tool output) is excluded in both environments, so production and development index the same Astro-rendered pages. The editorial entries remain only as the failure fallback.
Known metadata limits: PDTF-derived resources carry a DDD module, not a working-group domain, so the domain facet excludes them by design; decision status is the only filterable status because ontology and working-group statuses are uniform within their collections and appear as card labels instead.
Comments
Loading comments…
Sign in to post a comment