Your data
Docs and help centers
Records and settings for documentation and help centers: one record per section, so a search lands on the heading that answers it.
Readers search docs for a task or a term, and want the part of the page that covers it. Give each section its own record, and a search lands on the right heading with the matching words highlighted. The search on these docs works this way.
Records
One record per section, for each ## and ### heading, plus one for each page's introduction:
{
"objectID": "settings#synonyms",
"page": "Search settings",
"section": "Synonyms",
"group": "Guides",
"url": "/docs/settings#synonyms",
"text": "synonyms are groups of words or phrases that match each other: searching for any of them finds the others…",
"code": "",
"summary": "synonyms are groups of words or phrases that match each other: searching for any of them finds the others, ranked slightly below the word itself.",
"level": 3,
"order": 29
}- Sections, not pages. A whole page matches nearly any search about its topic, and opens at its top. A section matches what it covers, opens at its heading, and fits in the 16 KB a searchable field holds.
urlends with the heading's anchor, so a result opens at the section.textis plain text, without Markdown or HTML, so highlights and excerpts read well. Code goes in its own field, searched with less weight.summaryis the section's first sentence, to show when the match was in the heading.levelandorderput a page's introduction and main sections ahead of its subsections when results tie, in reading order.
Build the records from your Markdown or HTML when the site builds, and upload them with replaceAll on each deploy, so renamed and removed sections leave search.
Settings
{
searchableAttributes: [
{ field: "section", weight: 8 },
{ field: "page", weight: 4 },
{ field: "text", weight: 2 },
{ field: "code", weight: 1 },
],
facetFields: [],
filterFields: ["group"],
customRanking: [
{ field: "level", direction: "asc" },
{ field: "order", direction: "asc" },
],
synonyms: [["delete", "remove"], ["api key", "secret key"], ["autocomplete", "search as you type"]],
didYouMean: true,
languages: ["en"],
}- Headings first. They're short and say what a section is about, and the first two searchable fields hold 1 KB each, which suits them.
- Synonyms for your product's terms and the words readers use instead, such as "remove" for "delete".
groupas a filter lets a search box offer choices like "Guides only".
Search box
SearchDialog is the pattern docs sites use: a button that opens a search dialog, which ⌘K (Ctrl+K elsewhere) and / open too.
import { SearchDialog } from "@findlane/browser/react"
export function DocsSearch() {
return (
<SearchDialog
publicId="pub_your_public_id"
placeholder="Search the docs"
fields={["page", "section", "url", "summary"]}
hrefTemplate="{url}"
/>
)
}Show each result as "page › section", with an excerpt from Snippet around the matched words (see Highlights).
Questions and keywords
Every word in a search must match. languages leaves out common words such as "the" and "a", but not question words, so "how do I delete a record" only finds sections that also contain "how" and "do". Keywords such as "delete record" work best, and a placeholder can suggest them.
Private docs
Everything browser search can read is public. Docs for signed-in customers belong in their own index, searched from your server with a search key after you check who's asking.