# Combobox

> Searchable single select (WAI-ARIA combobox with a listbox popup).

Source: https://ui.jcsoftdev.com/docs/components/combobox

Searchable single select (WAI-ARIA combobox with a listbox popup). The input shows the typed
text while editing and the selected label otherwise; focus never leaves the input and the
highlighted option is announced through `aria-activedescendant`. Works with local options or
with results the caller loads from `onSearchChange`.

## Import

```ts
import { Combobox } from "@jcsoftdev/ui/forms";
```

Single-component entry points tree-shake to just this component: `@jcsoftdev/ui/forms/combobox`.

## Usage

```tsx
<Combobox
  aria-label="School"
  options={schools}
  placeholder="Search a school"
/>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `options` * | `readonly (ListboxOption \| ComboboxGroup)[]` |  | Options, optionally nested in labelled groups. For async search, pass the current results. |
| `value` | `string` |  | Selected option value (controlled). `""` means nothing is selected. |
| `defaultValue` | `string` | `""` |  |
| `onValueChange` | `((value: string, option: ComboboxOption \| null) => void)` |  |  |
| `onSearchChange` | `((query: string) => void)` |  | Called on every keystroke with the text typed, and with `""` when the search resets. Debounce in the caller before fetching; the component never delays or cancels requests. |
| `filter` | `boolean \| ((option: ComboboxOption, query: string) => boolean)` | `true` | Local filtering. `true` (default) matches label, description and keywords ignoring case and accents; `false` shows `options` as given (server-side search); a function decides per option. |
| `maxVisible` | `number` | `50` | Most options rendered at once. Default 50. |
| `loading` | `boolean` | `false` | Shows the loading status, e.g. while an async search is in flight. |
| `loadingText` | `string` |  |  |
| `emptyText` | `string` |  | Shown when nothing matches. Defaults to the localized "No results". |
| `clearable` | `boolean` | `true` | Shows a button that clears the selection. Default `true`. |
| `clearLabel` | `string` |  |  |
| `valueLabel` | `string` |  | Label to show for `value` while it is not (yet) among `options`, e.g. after an async search moved on. |
| `name` | `string` |  | Submits the value (not the typed text) with a surrounding `<form>` through a hidden input. |
| `invalid` | `boolean` |  |  |
| `nativeRequired` | `boolean` | `false` | `required` always sets `aria-required`. The native attribute, which blocks form submission with the browser's own bubble before your validation can render, is added only when this is `true`. Default `false`. |
| `size` | `"sm" \| "md"` | `"md"` |  |
| `container` | `HTMLElement \| null` |  | Portal target for the popup. Defaults to `document.body`; pass an element to keep a scoped `data-style`. |
| `material` | `"solid" \| "glass" \| "glass-clear" \| "liquid" \| "liquid-clear"` |  | Popup surface material; see `PopoverContent`. |
| `classNames` | `Partial<Record<ComboboxPart, string>>` |  | Per-part classes merged with `cn`; consumer classes win. `className` still targets the root and is merged last. |

`*` marks a required prop.

It also accepts the native props of the element or primitive it renders (for example `className`, `id`, `aria-*` and event handlers).

## Storybook stories

- [Default](/storybook/?path=/story/forms-combobox--default)
- [Keyboard](/storybook/?path=/story/forms-combobox--keyboard)
- [Escape Keeps The Selection](/storybook/?path=/story/forms-combobox--escape-keeps-the-selection)
- [Clearable](/storybook/?path=/story/forms-combobox--clearable)
- [Not Clearable](/storybook/?path=/story/forms-combobox--not-clearable)
- [Backspace Clears An Emptied Field](/storybook/?path=/story/forms-combobox--backspace-clears-an-emptied-field)
- [Submits The Value Not The Text](/storybook/?path=/story/forms-combobox--submits-the-value-not-the-text)
- [Inside Field](/storybook/?path=/story/forms-combobox--inside-field)
- [Groups And Custom Empty Text](/storybook/?path=/story/forms-combobox--groups-and-custom-empty-text)
- [Async Options](/storybook/?path=/story/forms-combobox--async-options)
- [Spanish](/storybook/?path=/story/forms-combobox--spanish)
- [Controlled](/storybook/?path=/story/forms-combobox--controlled)
- [Required Leaves Validation To The App](/storybook/?path=/story/forms-combobox--required-leaves-validation-to-the-app)
- [Native Required](/storybook/?path=/story/forms-combobox--native-required)

## Source

`packages/ui/src/forms/combobox/combobox.tsx`
