Header search bar with Cmd+K dialog - #671
Merged
Merged
Conversation
This was referenced Jun 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a sitewide search bar to the header that opens a Cmd+K (or Ctrl+K, or
/) dialog and fuzzy-matches across every editorial surface on the site: benchmarks, products, alternatives, answers, chains, compare pairs, and top-level pages.Stack
src/lib/search/buildIndex.ts, shipped once as JSON via the root layout. No/api/searchroute, no backend lookups.Index
Per-kind counts at build time:
benchmarks/*.yml(drafts skipped)src/data/provider-registry.tssrc/data/compare-pairs.tsalternatives/*.ymlanswers/*.ymlsrc/lib/chains.tsCHAINSJSON payload: ~90 KB raw / ~20 KB gzip (shipped once with the RSC payload of the root layout).
Bundle impact
Dialog + cmdk + Fuse are lazy-loaded via
next/dynamicon the first open of the dialog. The header trigger only adds an icon button and the provider plumbing to the shared chunk.Lazy chunk that holds cmdk + Fuse + the search dialog: 76 KB raw / ~25 KB gzip. Zero impact on first paint for pages that never open the dialog.
UX
/opens it (skipped when an input/textarea is already focused, GitHub-style).|separator on desktop. On mobile, a 44 by 44 icon-only button sits to the left of the hamburger.pm-data-freshness,aggregator-head-lag,l1-finality,rpc-capabilities).bg-paper,text-ink,border-rule, etc.). Nodark:variants needed.role="dialog",aria-modal="true",aria-label="Search"on the panel. Focus lands on the input. ESC, click outside, and a close button all dismiss.Files
New:
src/lib/search/types.tssrc/lib/search/buildIndex.tssrc/components/search/search-provider.tsx(client, Cmd+K listener + dynamic dialog)src/components/search/search-dialog.tsx(client, cmdk + Fuse)src/components/search/search-trigger.tsx(desktop/mobile variants)Modified:
src/app/layout.tsx(mounts<SearchProvider items={await buildSearchIndex()}>)src/components/site-header.tsx(drops the trigger in desktop nav + next to the hamburger)package.json/pnpm-lock.yaml(addscmdk,fuse.js)v2 ideas (out of scope)
/benchmarks/<slug>/<chain>) and category routeslocalStorageValidation
pnpm typecheckcleanpnpm validate31 specs OKpnpm test src/113 passespnpm lintno new issuespnpm buildsucceeds; dialog code lands in its own lazy chunkTest plan
/benchmarks/l1-finality/anywhere except inside a text input and confirm the dialog opens