SearchDialog
The search modal component for performing full-text search across documentation pages.
The SearchDialog provides an accessible, fully customizable overlayable command panel that lets users instantly search routes, headings, and descriptions.
Composable Search Dialog Example
Using the SearchDialog primitive subcomponents, you can compose a custom search window overlay. The following example shows how to wire the overlay to the search state hook and build a clean modal dialog with list results and custom icons:
// docs/components/CustomSearchDialog.tsx
import React from 'react'
import { SearchDialog } from 'boltdocs/primitives'
import { useSearch } from 'boltdocs/client'
export default function CustomSearchDialog() {
const { isOpen, close, query, setQuery, results } = useSearch()
return (
<SearchDialog
isOpen={isOpen}
onOpenChange={(open) => !open && close()}
className="bg-black/40 backdrop-blur-xs flex items-center justify-center p-4 transition-all"
>
<SearchDialog.Content className="w-full max-w-xl bg-white dark:bg-zinc-900 border border-subtle rounded-xl shadow-2xl overflow-hidden">
<SearchDialog.Dialog>
{/* 1. Styled Search Input in the Header */}
<SearchDialog.Input className="flex items-center border-b border-subtle px-4 py-3">
<SearchDialog.Input.SearchInput
value={query}
onChange={(e) => setQuery((e.target as HTMLInputElement).value)}
placeholder="Search documentation..."
className="text-sm placeholder-zinc-400 outline-none"
/>
{query && (
<SearchDialog.Input.Button className="text-xs text-muted hover:text-body">
Clear
</SearchDialog.Input.Button>
)}
</SearchDialog.Input>
{/* 2. Scrollable Results List Box */}
{results.length > 0 && (
<SearchDialog.Autocomplete>
<SearchDialog.List className="p-2 max-h-96 overflow-y-auto space-y-1">
{results.map((item) => (
<SearchDialog.Item
key={item.path}
id={item.path}
className="p-2.5 rounded-lg transition-colors hover:bg-zinc-100 dark:hover:bg-zinc-800"
>
{/* Visual indicators for regular pages vs. deep headings */}
<SearchDialog.Item.Icon
isHeading={item.path.includes('#')}
className="text-muted mr-3"
/>
<SearchDialog.Item.Title className="text-sm font-medium text-body">
{item.title}
</SearchDialog.Item.Title>
{item.description && (
<SearchDialog.Item.Bio className="text-xs text-muted">
{item.description}
</SearchDialog.Item.Bio>
)}
</SearchDialog.Item>
))}
</SearchDialog.List>
</SearchDialog.Autocomplete>
)}
{/* Empty fallback message */}
{query && results.length === 0 && (
<div className="p-8 text-center text-sm text-muted">
No results found for "{query}"
</div>
)}
</SearchDialog.Dialog>
</SearchDialog.Content>
</SearchDialog>
)
}
Composable Subcomponents
The SearchDialog primitive provides the following subcomponents for structure customization:
| Component | HTML Tag | Description | Props |
|---|---|---|---|
SearchDialog / SearchDialog.Overlay | <div> (Backdrop) | The background overlay element dimming the page backdrop. | ModalOverlayProps |
SearchDialog.Content | <div> (Modal) | The floating dialog layout wrapper containing the dialog shell. | ModalProps |
SearchDialog.Dialog | <dialog> | The interactive dialog container mapping focus and keyboard controls. | DialogProps |
SearchDialog.Input | <div> | Wraps the search input form layout. | SearchFieldProps |
SearchDialog.Input.SearchInput | <input> | The inner text input control itself. | InputProps |
SearchDialog.Input.Button | <button> | A button to clear the active input query text. | ButtonProps with slot="clear" |
SearchDialog.Autocomplete | <div> | A wrapper aligning query and autocomplete list highlights. | AutocompleteProps |
SearchDialog.List | <ul> | The scrollable vertical list viewport of results. | ListBoxProps |
SearchDialog.Item | <li> | The individual result cell item. | SearchDialogItemProps |
SearchDialog.Item.Icon | <span> | Renders standard result indicators (hash # for headings, sheet for pages). | Icon Props |
SearchDialog.Item.Title | <div> | The main matching result text label. | ComponentBaseProps |
SearchDialog.Item.Bio | <div> | Supporting description context or section excerpt label. | ComponentBaseProps |
Component Props
ComponentBaseProps (Common)
| Property | Type | Default | Description |
|---|---|---|---|
children | ReactNode | undefined | Child content elements. |
className | string | undefined | Custom utility CSS classes. |
style | CSSProperties | undefined | Inline style settings. |
ModalOverlayProps and ModalProps
Inherits the standard React-Aria ModalOverlayProps and ModalProps settings (e.g., isOpen, onOpenChange, isDismissable).
DialogProps
Inherits the standard React-Aria DialogProps settings.
SearchFieldProps
Inherits the standard React-Aria SearchFieldProps settings (e.g., value, onChange).
InputProps
Inherits the standard HTML input element properties.
AutocompleteProps
Custom wrapper settings handling search query term highlighting.
ListBoxProps
Inherits standard React-Aria ListBoxProps (e.g., items, selectionMode).
SearchDialogItemProps
| Property | Type | Default | Description |
|---|---|---|---|
id | Key | Required | Unique index key of the item. |
textValue | string | Required | Raw text content for keyboard search. |
renderHint | (state: { isSelected?: boolean; isFocused?: boolean }) => ReactNode | (default hint) | Custom function that replaces the default "Select" + shortcut-key hint. |
Icon Props
| Property | Type | Default | Description |
|---|---|---|---|
isHeading | boolean | false | When true, renders a heading section icon. Otherwise renders a document page icon. |
icon | ReactNode | (hash or file icon) | Custom leading icon that replaces the default hash/file icon. |
Customization & states
The SearchDialog primitive is style-neutral: it ships the overlay, dialog, list, and item behavior from React Aria, and every visual decision belongs to the theme through its className slots. Item state is exposed as data-* attributes on SearchDialog.Item, present only when true.
| State / Slot | Mechanism |
|---|---|
SearchDialog (root) | <div> backdrop overlay; mounted only while open |
SearchDialog.Content / Dialog | Modal surface and <dialog>; size and colors via className |
SearchDialog.Input.SearchInput | Bare <input>; focus and placeholder styles via className |
SearchDialog.List | <ul> results viewport; scroll-area styling via className |
SearchDialog.Item | RAC ListBoxItem; emits data-selected when the result is selected |
| Keyboard highlight | The focused item exposes data-focused (and data-focus-visible) |
<SearchDialog.List className="max-h-96 overflow-y-auto p-2">
{results.map((item) => (
<SearchDialog.Item
key={item.path}
id={item.path}
className="rounded-lg p-2.5 text-body transition-colors data-focused:bg-surface data-focused:outline-none data-selected:bg-primary-500/10"
>
<SearchDialog.Item.Title>{item.title}</SearchDialog.Item.Title>
</SearchDialog.Item>
))}
</SearchDialog.List>