# Searchable Select

> A select with a search field inside its popup, on Base UI's Combobox. Results stay grouped and bold the matching text, rows take an avatar or icon plus secondary text, and there's an empty state, a Create row for new entries and async loading with a spinner row. Arrow keys move through results from the search field, Enter picks and Escape closes.

- Slug: `searchable-select`
- Category: [Selects](https://www.assembli.design/category/selects.md)
- Type: component
- Tags: combobox, select, search, autocomplete, async, creatable
- npm dependencies: @base-ui/react, lucide-react
- shadcn/ui dependencies: none
- Live preview: https://www.assembli.design/preview/searchable-select
- Page: https://www.assembli.design/components/searchable-select

![Searchable Select preview](https://www.assembli.design/thumbnails/searchable-select-light.png)

## Props

Other props pass through to the root element.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `options` | `Entry[]` | `[]` | Options or labelled groups to search locally. |
| `loadOptions` | `(query: string, signal: AbortSignal) => Promise<Entry[]>` |  | Loads results from a server as the query changes (debounced). Replaces local filtering. |
| `value` | `string \| null` |  |  |
| `defaultValue` | `string \| null` | `null` |  |
| `onValueChange` | `(value: string \| null, option: SearchableOption \| null) => void` |  |  |
| `onCreate` | `(query: string) => SearchableOption \| Promise<SearchableOption \| void> \| void` |  | Adds a "Create '…'" row when nothing matches exactly. Return the new option (or a promise of it) to pick it. |
| `label` | `React.ReactNode` |  |  |
| `hint` | `React.ReactNode` |  | Quiet text to the right of the label, such as "Optional". |
| `description` | `React.ReactNode` |  |  |
| `error` | `React.ReactNode` |  | Replaces the description and marks the trigger `aria-invalid`. |
| `placeholder` | `React.ReactNode` | `"Select…"` |  |
| `searchPlaceholder` | `string` | `"Search…"` |  |
| `emptyMessage` | `(query: string) => React.ReactNode` |  | Shown when the search finds nothing. Gets the query. |
| `leading` | `React.ReactNode` |  | A field icon before the value. A picked option's icon or avatar takes its place. |
| `size` | `SelectSize` | `"md"` |  |
| `disabled` | `boolean` |  |  |
| `required` | `boolean` |  |  |
| `name` | `string` |  | Submits the picked value with a surrounding form. |
| `open` | `boolean` |  |  |
| `defaultOpen` | `boolean` |  |  |
| `onOpenChange` | `(open: boolean) => void` |  |  |
| `debounce` | `number` | `250` | Delay before `loadOptions` runs, in ms. Defaults to 250. |
| `triggerClassName` | `string` |  | Classes for the trigger; `className` goes on the root. |

## Install

One-time setup (needs a subscription):

1. Add the registry to the project's `components.json`: `{"@assembli":{"url":"https://www.assembli.design/r/{name}.json","headers":{"Authorization":"Bearer ${ASSEMBLI_API_KEY}"}}}` (merge into `"registries"`).
2. Put an API key from https://www.assembli.design/account in `.env.local` as `ASSEMBLI_API_KEY=asm_…`.

Then install with the shadcn CLI (writes `components/searchable-select/searchable-select.tsx` and installs dependencies):

```bash
npx shadcn@latest add @assembli/searchable-select
```

Registry item JSON: https://www.assembli.design/r/searchable-select.json (send `Authorization: Bearer <api key>`)

## Code

> Component source needs an Assembli subscription ($12/month or $96/year) and an API key sent as `Authorization: Bearer <key>`. To get one without copying anything, POST https://www.assembli.design/api/agent/login (or call the MCP tool connect_account), show the user the link it returns, and poll https://www.assembli.design/api/agent/token for the key. Or subscribe at https://www.assembli.design/pricing and create a key at https://www.assembli.design/account.
