Top-bar search: NavSearch jumps to pages and actions; SmartSearch queries records with grouped results.
NavSearch filters a fixed list of destinations with a keyboard shortcut (Ctrl or Cmd K). SmartSearch takes an async search function with abort signals and renders grouped record results with highlighting.
Installation
npx shadcn@latest add KezLahd/rime/nav-searchAlso installs: base, icon, search-field.
Usage
import { NavSearch, SmartSearch } from "@/components/ui";
<NavSearch aria-label="Search pages" items={DESTINATIONS} />Examples
Open
NavSearch
API
Generated from the component's TypeScript types and JSDoc (scripts/gen-ui-registry.mjs), so it always matches the source.
NavSearch
| Prop | Type | Default | Description |
|---|---|---|---|
| itemsRequired | ReadonlyArray<NavSearchItem> | ||
| recent | ReadonlyArray<string> | Ids of recently opened items, newest first. Listed under "Recent" above everything else while the search is empty. The host keeps the list (from onSelect), so it can live wherever the rest of the session does. | |
| onSelect | (item: NavSearchItem) => boolean | void | Runs before navigating. Return false to stay put (the styleguide does, and a host can to open a dialog instead). | |
| placeholder | string | "Search pages and actions" | |
| shortcut | string | null | "k" | Ctrl/⌘ + this letter opens the search from anywhere. Pass null to turn it off. |
| width | number | string | 340 | Width of the bar, and the least width of its results. |
| aria-label | string | Names the search for assistive tech. | |
| className | string | ||
| inline | boolean | false | Show the results panel open, in place under the bar: no portal, no outside-click listener, no scrolling into view. For docs and thumbnails. |
SmartSearch
| Prop | Type | Default | Description |
|---|---|---|---|
| searchRequired | (query: string, signal: AbortSignal) => Promise<SmartSearchGroup[]> | Runs the search. Called once typing pauses, with a signal that aborts when the query changes, so a slow answer to "ha" never lands on top of "cooper". Reject (anything but an AbortError) to show the error state. | |
| onSelectRequired | (result: SmartSearchResult, context: SmartSearchSelectContext) => boolean | void | A result was chosen (Enter or click). The host records it in recent searches. Return false to stay put; otherwise a result with an href is navigated to. | |
| onViewAll | (query: string) => void | "View all results": the footer row, and Enter with no row highlighted. Omit to leave both out. | |
| recent | ReadonlyArray<string> | Earlier queries, newest first. Offered while the field is focused and empty. | |
| placeholder | string | "Search" | |
| minChars | number | 2 | Characters before a search runs. Defaults to 2: one letter matches most of a database. |
| debounceMs | number | 180 | Pause after the last keystroke before searching. |
| renderResult | (result: SmartSearchResult, state: SmartSearchResultState) => ReactNode | Replaces the default row body (tile, text, meta, hint are all yours). | |
| emptyHint | ReactNode | Shown when focused and empty with no recent searches: say what can be searched for. | |
| noResultsHint | (query: string) => ReactNode | Suggestion under "No results for …". | |
| size | "sm" | "md" | "md" | |
| shortcut | string | Ctrl/⌘ + this letter focuses the field. Use once per page. | |
| disabled | boolean | ||
| id | string | ||
| aria-label | string | Needed unless a <Field> labels it. | |
| className | string |
Theme tokens
Per-component tokens are undeclared by default, so the default shown is the fallback the CSS uses. Set one at :root (or in theme.css) to restyle every instance. Live values are read from this page, so they follow the Rime Studio.
This component has no tokens of its own; it reads the system tokens below.
System tokens it reads
| Token | Default | Live value |
|---|---|---|
| --blur-chrome | tokens.css | … |
| --brand-gradient | tokens.css | … |
| --brand-gradient-soft | tokens.css | … |
| --danger-ink | tokens.css | … |
| --dur | tokens.css | … |
| --dur-fast | tokens.css | … |
| --ease | tokens.css | … |
| --ease-out | tokens.css | … |
| --focus-halo | tokens.css | … |
| --focus-ring | tokens.css | … |
| --font-body | tokens.css | … |
| --glass-edge | tokens.css | … |
| --glass-fill-chrome | tokens.css | … |
| --glow-sm | tokens.css | … |
| --ink-body | tokens.css | … |
| --ink-brand | tokens.css | … |
| --ink-heading | tokens.css | … |
| --ink-inverse | tokens.css | … |
| --ink-muted | tokens.css | … |
| --ink-secondary | tokens.css | … |
| --line | tokens.css | … |
| --line-brand | tokens.css | … |
| --line-brand-strong | tokens.css | … |
| --line-soft | tokens.css | … |
| --r-2xs | tokens.css | … |
| --r-full | tokens.css | … |
| --r-lg | tokens.css | … |
| --r-md | tokens.css | … |
| --r-sm | tokens.css | … |
| --rgb-brand-deep | tokens.css | … |
| --rgb-white | tokens.css | … |
| --shadow-chrome | tokens.css | … |
| --shadow-chrome-open | tokens.css | … |
| --shadow-float | tokens.css | … |
| --surface-solid | tokens.css | … |
| --text-caption | tokens.css | … |
| --text-micro | tokens.css | … |
| --text-small | tokens.css | … |
| --tracking-label | tokens.css | … |
| --wash-active | tokens.css | … |
| --wash-hover | tokens.css | … |
| --wash-row | tokens.css | … |
| --wash-strong | tokens.css | … |
| --wash-subtle | tokens.css | … |
| --z-popover | tokens.css | … |
Accessibility
- Combobox with a listbox of results; the shortcut is announced in the hint.
Do and don't
Do
- Keep NavSearch items to real destinations.
Don't
- Don't use SmartSearch without debouncing on the server side too.
For AI agents
This page as markdown, rendered from the same registry entry. Point an agent at it (or add .md to this page's URL), or at /llms.txt for the index.
Open nav-search.md