# 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.

<span id="two-engines-one-component" />

## 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:

| Marker | Where the shell puts it | Effect |
| --- | --- | --- |
| `data-pagefind-body` | `main.doc-content` — except on `noindex` pages | Only page content is indexed, never chrome (sidebar, topbar, rails). |
| `data-pagefind-ignore` | Breadcrumbs, prev/next footer | Excluded even inside the body. |
| `data-pagefind-meta="hidden:true"` | Pages with `hidden: true` | Indexed 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](/guides/site-config.md)) — 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.

> **Note:** 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](/reference/components/shell.md) owns the open state and query, renders
the [Topbar](/reference/components/topbar.md) search field, and mounts the palette:

```tsx

 setSearchOpen(false)} query={query} />
```

## Props

| Prop | Type | Description |
| --- | --- | --- |
| `open` | `boolean` | Whether the palette is showing. |
| `onClose` | `() => void` | Called on Esc / backdrop click. |
| `query` | `string` | The 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.
