Search
Add fast, local documentation search without operating a search service.
This functionality is already configured in the starter templates. Follow the complete setup in the Quickstart.
Heyo Docs includes a local search interface in the built-in Grain theme. It
builds its index in the browser from the documentation model already passed to
DocsApp, so there is no hosted search provider, API key, crawler, or search
endpoint to configure.
The search dialog opens from the sidebar or top navigation. Users can also press ⌘ K on macOS or Ctrl K elsewhere, navigate with the arrow keys, and open the selected page with Enter.
What is indexed
Every MDX page contributes its title, frontmatter description, table-of- contents headings, and plain-text body. The build step removes frontmatter, code blocks, images, links, and MDX tags from the body before sending it to the browser index.
Generated OpenAPI reference pages are indexed too. Their title, description, HTTP method, path, operation ID, tags, and parameter names are searchable. The full OpenAPI document is not included merely to support search.
The built-in index uses ZBSearch. It returns at most eight results, gives title matches more weight than descriptions and body text, and tolerates a small amount of typo variation. The index is local to the current browser session; queries are not sent to a Heyo Docs server.
Start with a template
Projects generated for React Router, Next.js, and Astro already render the
search UI through DocsApp. Add useful titles, descriptions, and headings to
your MDX content, then run the app:
bun create @heyo-sh/heyo-docs my-docs --template react-routerNo extra search configuration is required. The included Grain theme supplies
the Search component and DocsApp supplies the MDX and OpenAPI records that
it indexes.
Searchable content
Use frontmatter and descriptive headings to make the result list useful. The description is both an SEO field and the preferred excerpt shown by the search dialog.
---title: Configure webhooksdescription: Verify signed webhook deliveries from the API.---# Configure webhooks## Verify the signatureUse the signing secret to validate every incoming request.Avoid treating the in-browser index as an access-control boundary. A page that
is supplied to DocsApp is available to people who can load the documentation
application.
Use the search primitives
The search engine is exported independently of the UI. This is useful when a custom theme needs a different interaction model while retaining the same matching, ranking, and result limit.
import {
createSearchIndex,
findSearchPages,
type SearchDocument,
} from "@heyo-sh/heyo-docs";
const pages: SearchDocument[] = [
{
slug: "/webhooks",
title: "Configure webhooks",
description: "Verify signed webhook deliveries from the API.",
tableOfContents: [
{ id: "verify-the-signature", title: "Verify the signature", depth: 2 },
],
searchContent: "Use the signing secret to validate every incoming request.",
},
];
const index = createSearchIndex(pages);
const results = findSearchPages(index, "webhook signature");Call createSearchIndex() once for a stable set of pages, then use
findSearchPages() for each query. searchPages(pages, query) is available
when retaining the index is unnecessary.
Custom themes
Search is a theme capability, not a separate application route. DocsApp
checks whether the active theme provides a Search component and supplies it
with the complete set of searchable MDX and OpenAPI records. A theme can omit
that component to hide search, or provide its own component that receives the
same SearchDocument[] data.
The default dialog also handles focus, accessible listbox semantics, result highlighting, and keyboard selection. Reuse it when those interactions suit the design; use the exported primitives when they do not.