Search
On this page 33
BunPress includes built-in search functionality for your documentation site. This guide covers configuration and customization options.
Quick Start
Enable search in your configuration:
// bunpress.config.ts
export default {
search: {
enabled: true,
},
}
Search Providers
Built-in Search
BunPress includes a fast, client-side search:
export default {
search: {
provider: 'local', // default
},
}
Algolia DocSearch
For larger documentation sites:
export default {
search: {
provider: 'algolia',
algolia: {
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_SEARCH_API_KEY',
indexName: 'YOUR_INDEX_NAME',
},
},
}
Local Search Options
Indexing Configuration
export default {
search: {
provider: 'local',
options: {
// Include/exclude patterns
include: ['**/*.md'],
exclude: ['**/node_modules/**', '**/draft/**'],
// Search fields
searchFields: ['title', 'content', 'headings', 'keywords'],
// Result options
maxResults: 10,
minQueryLength: 2,
},
},
}
searchFields names map onto each indexed section:
| Field | What it matches |
|---|---|
title | The section's own heading (the page title for the lead section) |
headings | The title of the page the section belongs to |
content | The section's prose, with code blocks removed |
keywords | Terms added in the page's frontmatter |
Boosting
Prioritize certain content:
export default {
search: {
options: {
boost: {
title: 10,
headings: 5,
content: 1,
},
},
},
}
UI Customization
Placeholder Text
export default {
search: {
placeholder: 'Search documentation...',
},
}
Keyboard Shortcut
export default {
search: {
shortcut: '/', // Press / to focus search
// or
shortcut: ['ctrl', 'k'], // Ctrl+K
},
}
Result Appearance
export default {
search: {
resultOptions: {
showDescription: true,
descriptionLength: 150,
highlightMatches: true,
showPath: true,
},
},
}
Styling
The dialog exposes both its own BPSearch-* classes and the stable aliases
below. The aliases are what this guide targets, so they are safe to style.
Custom CSS
/_ Search input _/
.search-input {
background: var(--vp-c-bg-soft);
border: 1px solid var(--vp-c-divider);
border-radius: 8px;
padding: 0.5rem 1rem;
}
/_ Search modal _/
.search-modal {
background: var(--vp-c-bg);
border-radius: 12px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}
/_ Search results _/
.search-result {
padding: 0.75rem 1rem;
border-bottom: 1px solid var(--vp-c-divider);
}
.search-result:hover {
background: var(--vp-c-bg-soft);
}
/_ Highlighted matches _/
.search-highlight {
background: rgba(255, 213, 0, 0.3);
padding: 0.1em 0.2em;
border-radius: 2px;
}
Advanced Configuration
Custom Tokenizer
export default {
search: {
options: {
tokenize: (text) => {
// Custom tokenization logic
return text
.toLowerCase()
.split(/[\s\-_]+/)
.filter((token) => token.length > 1)
},
},
},
}
Fuzzy Matching
export default {
search: {
options: {
fuzzy: true,
fuzziness: 2, // Max edit distance
},
},
}
Stemming
export default {
search: {
options: {
stemmer: 'english', // Use English stemmer
},
},
}
Frontmatter Control
Exclude Pages
---
search: false
---
# This page won't be indexed
Custom Search Keywords
---
search:
keywords:
- alternative name
- common misspelling
---
Search Title Override
---
search:
title: Custom Search Title
---
Search Analytics
Track Searches
export default {
search: {
onSearch: (query, results) => {
// Track search analytics
analytics.track('search', {
query,
resultCount: results.length,
})
},
},
}
onSearch and options.tokenize run in the browser, so they are serialized
into the page. They may reference globals that exist there (like analytics
above) but must not close over values from your config module — those do not
survive the trip.
If you would rather not ship a function, listen for the event the dialog dispatches after every search:
document.addEventListener('bp:search', (event) => {
const { query, results } = event.detail
})
Algolia DocSearch
Setup
- Apply at docsearch.algolia.com
- Configure once approved:
export default {
search: {
provider: 'algolia',
algolia: {
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_SEARCH_ONLY_API_KEY',
indexName: 'your_index',
searchParameters: {
facetFilters: ['language:en'],
},
},
},
}
Crawler Configuration
{
"index_name": "your_index",
"start_urls": ["https://your-docs.com/"],
"selectors": {
"lvl0": ".sidebar-heading.active",
"lvl1": "article h1",
"lvl2": "article h2",
"lvl3": "article h3",
"content": "article p, article li"
}
}
Performance
Lazy Loading
export default {
search: {
lazy: true, // Load search index on demand
},
}
Index Size
export default {
search: {
options: {
// Reduce index size
storeFields: ['title'], // `url` is always kept
maxContentLength: 500, // Limit prose per section
},
},
}
Prebuilt Index
The index is written to search-index.json on every build, alongside the
generated pages. Skip it when you do not need search in a given build:
bunpress build --no-search-index
Accessibility
Search is accessible by default:
- Keyboard navigation
- ARIA labels
- Focus management
- Screen reader support
Best Practices
- Meaningful titles: Use descriptive page titles
- Clear headings: Well-structured headings improve search
- Keywords: Add search keywords in frontmatter
- Test searches: Verify common queries return expected results
- Monitor analytics: Track search patterns to improve content
Related
- Configuration - Full configuration options
- SEO - Search engine optimization
- Performance - Site performance