DreamLake

Search

Dockit search has two engines behind one UI, SearchPalette. Press ⌘K or /, or click the topbar search field. Results update as you type; ↑↓ selects a result, Enter opens it, and Esc closes the overlay. The right pane previews the selected page as rendered Markdown. This page explains what gets indexed when, how the shell scopes the index, and how authoring choices affect findability.

Production: pagefind

The build's final step indexes the prerendered HTML:

bash
pagefind --site dist/client

Pagefind ships a WASM index the browser loads on demand — sub-word matching, excerpts with <mark> highlights, and it scales with page count.

The shell emits the scoping markers itself; there is nothing to add to your pages:

MarkerWhere the shell puts itEffect
data-pagefind-bodymain.doc-content — except on noindex pagesOnly page content is indexed, never chrome (sidebar, topbar, rails).
data-pagefind-ignoreBreadcrumbs, prev/next footerExcluded even inside the body.
data-pagefind-meta="hidden:true"Pages with hidden: trueIndexed but filtered from results unless dev mode (Cmd+Shift+D) is on.

Pages with noindex: true are skipped entirely — the shell omits data-pagefind-body on them, and pagefind indexes nothing on a page without that marker, so they never enter the pagefind index.

Dev: the fallback index

vite dev has no prerendered HTML, so initSearchIndex builds an in-memory index from the raw MDX you pass to initDocs (the ?raw glob — see Site config) — frontmatter stripped, code fences dropped, headings captured for higher-weight ranking. Rank order: title match → heading match → description → section → body occurrences → fuzzy title subsequence.

The engine switch is automatic — searchPages() tries pagefind and falls back. The palette also uses the raw markdown for its preview pane in both modes.

Writing searchable pages

  • Titles carry the most weight — name pages what readers will type.
  • description doubles as the result blurb; a missing one falls back to body context around the match.
  • Headings are the second-strongest signal — real H2/H3 structure beats bold paragraphs.
  • Code fences are excluded from the dev index — put key terms in prose too, not only in code.
Search in this order

If a result surprises you in dev but not production (or vice versa), remember the engines differ: pagefind matches sub-words against rendered HTML; the fallback matches whole substrings against stripped markdown.

Wiring

The Layout owns the open state and query, renders the Topbar search field, and mounts the palette:

tsx
import { SearchPalette } from '@dreamlake/dockit'

<SearchPalette open={searchOpen} onClose={() => setSearchOpen(false)} query={query} />

Props

PropTypeDescription
openbooleanWhether the palette is showing.
onClose() => voidCalled on Esc / backdrop click.
querystringThe live query (the input lives in the Topbar, not the palette).

Behavior notes

  • hidden: true pages are excluded from results unless dev mode (Cmd+Shift+D) is on; noindex pages never enter the pagefind index at all.
  • The panel is resizable (drag the bottom edge); split position and height persist in localStorage.
  • Below 640px the palette collapses to a single column and drops the preview pane.