# Select Search (/docs/select-search)

A searchable Base UI select for larger option sets.

## Install

```bash
npx shadcn@latest add https://4af.selfsimilar.dev/r/select-search.json
```

## Usage

```tsx
import { SearchSelect, SearchSelectInput, SearchSelectContent, SearchSelectItem } from "@/components/ui/select-search";

// Focusing dims the selection; clicking a row commits it and unfocuses the field.
<SearchSelect items={items} defaultValue={items[0]}>
  <SearchSelectInput aria-label="Choose an option" placeholder="Search…" />
  <SearchSelectContent>
    {(item) => <SearchSelectItem key={item.value} value={item}>{item.label}</SearchSelectItem>}
  </SearchSelectContent>
</SearchSelect>
```

## API

**Main exports:** `SearchSelect`, `SearchSelectInput`, `SearchSelectContent`, and item parts

An editable Combobox-style trigger with live filtering, single or checkbox-based multi-selection,
icons, and full keyboard and ARIA behaviour.

## Searching and cancelling

In single-select mode:

- The selected value shows in normal text, and dims while the field is focused. Typing starts a
  new query over it.
- Opening highlights the current selection; typing highlights the top match.
- Choosing a row commits it. Clicking a row also unfocuses the field; selecting with the keyboard
  keeps focus.
- Escape discards the query and keeps focus. Clicking outside, or deleting the query, keeps the
  current selection.
- When the selection has an icon, focusing the field swaps it for a dimmed search icon until the
  field loses focus.

In multi-select mode the panel stays open for more choices.

`inputValue` / `defaultInputValue` and `onInputValueChange` hold the search query, separately
from `value` / `defaultValue` and `onValueChange`. `itemToStringLabel` also supplies the selected
label for custom item shapes. Multi-select shows a count summary and checkboxes.

## Sizing

`size="sm"` is the 30px compact control and `size="md"` is the 34px form-row control.
The input trigger and its option rows share the selected size, and the input uses the matching
button radius: 6px for `sm` and 8px for `md`.

## Item data

An item is its own value (`<SearchSelectItem value={item}>`), so the icon goes on the item
object. Do this when a preselected value must show its icon before the panel has opened:

```tsx
const fruits = [{ value: "apple", label: "Apple", icon: <Apple /> }];

<SearchSelect items={fruits} defaultValue={fruits[0]}>
```

An icon passed only to `SearchSelectItem` is available after the panel mounts. Resolution order
is the mounted item, then `iconForValue`, then the value's own `icon`.

## Highlight implementation

Opening activates the current selection, or the most recently selected value in multi-select;
without a selection it activates the first enabled row. A query activates the top match, and
leaving the panel keeps the active row.

The Base UI integration uses `autoHighlight="always"` only when nothing is selected: that mode
pins the first row over an existing selection. With a selection, plain `autoHighlight` restores
it. Keep `keepHighlight` enabled so pointer exit does not clear the mark and reset Enter's target.