# NavSearch and SmartSearch

> Top-bar search: NavSearch jumps to pages and actions; SmartSearch queries records with grouped results.

Category: Navigation. Docs page: https://rime.mjsons.net/components/nav-search

## Installation

```bash
npx shadcn@latest add KezLahd/rime/nav-search
```

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.

## Usage

```tsx
import { NavSearch, SmartSearch } from "@/components/ui";

<NavSearch aria-label="Search pages" items={DESTINATIONS} />
```

## Props: NavSearch

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` (required) | `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. |

## Props: SmartSearch

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `search` (required) | `(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. |
| `onSelect` (required) | `(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` |  |  |

## Examples

### Open

inline shows the results panel open under the bar, in place.

```tsx
<NavSearch inline aria-label="Search pages and actions" items={DESTINATIONS} />
```

### NavSearch

```tsx
<NavSearch items={DESTINATIONS} aria-label="Search pages and actions" />
```

## Theme tokens

System tokens it reads: `--blur-chrome`, `--brand-gradient`, `--brand-gradient-soft`, `--danger-ink`, `--dur`, `--dur-fast`, `--ease`, `--ease-out`, `--focus-halo`, `--focus-ring`, `--font-body`, `--glass-edge`, `--glass-fill-chrome`, `--glow-sm`, `--ink-body`, `--ink-brand`, `--ink-heading`, `--ink-inverse`, `--ink-muted`, `--ink-secondary`, `--line`, `--line-brand`, `--line-brand-strong`, `--line-soft`, `--r-2xs`, `--r-full`, `--r-lg`, `--r-md`, `--r-sm`, `--rgb-brand-deep`, `--rgb-white`, `--shadow-chrome`, `--shadow-chrome-open`, `--shadow-float`, `--surface-solid`, `--text-caption`, `--text-micro`, `--text-small`, `--tracking-label`, `--wash-active`, `--wash-hover`, `--wash-row`, `--wash-strong`, `--wash-subtle`, `--z-popover`.

## Accessibility

- Combobox with a listbox of results; the shortcut is announced in the hint.

## Do

- Keep NavSearch items to real destinations.

## Don't

- Don't use SmartSearch without debouncing on the server side too.
