Orientation
Content Processing
Search Infrastructure
Rendering and UI
Developer Tooling
How It Works
The following files were used as context for generating this wiki page:
Search Dialogs are a core feature of the UI subsystem, providing a centralized interface for users to discover content across documentation sets. By offering a standardized way to invoke and navigate search results, these components ensure a consistent user experience while remaining decoupled from specific search backends. They act as a bridge between high-level application state and low-level search implementation details.
The design relies on a provider-based architecture, allowing the search functionality to be configured and injected throughout the application. This modularity enables developers to swap out search providers—such as the default fetch-based search, Algolia, or Orama—without modifying the consumption layer. By providing a clean API surface for triggers and content, the system facilitates rapid integration into various layouts.
Internally, the Search Dialog subsystem manages complex state, including keyboard navigation, focus trapping, and asynchronous loading states. It leverages React context to share search input and selection logic among diverse components, ensuring that triggers, inputs, and results stay synchronized. This architecture minimizes boilerplate while offering hooks for advanced customizations, such as filtering and metadata display.
The search system is initialized through a SearchProvider, which manages the global search state including the "open" boolean and the configuration of the dialog component.
Sources: packages/base-ui/src/contexts/search.tsx:112-162, packages/base-ui/src/components/dialog/search.tsx:56-63
The SearchProvider acts as the single source of truth for whether the search modal should be displayed. It subscribes to global keyboard events (defaulting to Meta+K) to trigger the setIsOpen state function, ensuring immediate accessibility.
Sources: packages/base-ui/src/contexts/search.tsx:121-133
The SearchDialog acts as a controlled component wrapping the Radix Dialog.Root. It uses an internal context to distribute the search change and selection handlers down the tree.
Tip
The use of useRef for callbacks in SearchDialog prevents unnecessary re-renders of the entire dialog tree when the parent’s search state updates, optimizing performance for fast-typing users.
Sources: packages/base-ui/src/components/dialog/search.tsx:177-213
When an item is selected in the list, the onSelect function determines the navigation target. It checks the item type and dispatches to the router if it's a standard page, or executes an onSelect function if the item is an action.
Sources: packages/base-ui/src/components/dialog/search.tsx:181-192
Keyboard navigation is handled within SearchDialogList. The component uses useEffectEvent to track the active state and allows users to traverse results using arrow keys.
Warning
The logic within SearchDialogList ensures that list indices loop correctly using the modulo operator: setActive(items.at(idx % items.length)?.id ?? null). This prevents out-of-bounds access.
Sources: packages/base-ui/src/components/dialog/search.tsx:339-358
The system exposes a standard interface for custom search backends. By wrapping useDocsSearch with specific client drivers, it unifies diverse API structures into the SortedResult interface.
Sources: packages/base-ui/src/components/dialog/search-default.tsx:63-70, packages/base-ui/src/components/dialog/search-algolia.tsx:61-67, packages/base-ui/src/components/dialog/search-orama.tsx:68-76
The SearchDialogListItem uses a renderMarkdown function to render search results. This renderer is configured with specific components to handle highlighted matches, links, and code blocks within the snippet display.
Sources: packages/base-ui/src/components/dialog/search.tsx:425-470
The list item component distinguishes between types (page, heading, text) and styles them accordingly, often applying specific padding and icons to indicate hierarchical structure.
Sources: packages/base-ui/src/components/dialog/search.tsx:451-468
To build a custom dialog, create a component that implements the SharedProps and utilizes the exported UI sub-components from the search module.
import {
SearchDialog,
SearchDialogHeader,
SearchDialogInput,
SearchDialogList,
type SharedProps
} from 'fumadocs-ui/components/dialog/search';
export default function MyCustomSearch(props: SharedProps) {
const [search, setSearch] = useState('');
// Implementation of query logic here...
return (
<SearchDialog search={search} onSearchChange={setSearch} {...props}>
<SearchDialogHeader>
<SearchDialogInput />
</SearchDialogHeader>
<SearchDialogList items={...} />
</SearchDialog>
);
}Sources: packages/create-app/template/+orama-cloud/@app/components/search.tsx:4-54