

# Combobox

Headless combobox built on React Aria `ComboBox`. Compose `Root`, `Label`, `Input`,
`Description`, `Error`, `Popover`, `ListBox`, and `Item` for autocompletes, searchable
selects, and other filterable pickers.

For the common single-select search field, use [`Typeahead`](/components/typeahead) instead.

## Examples

### Default

```tsx
import { Combobox } from '@var-ui/react';

const options = [
  { id: 'apple', label: 'Apple' },
  { id: 'plum', label: 'Plum' },
  { id: 'orange', label: 'Orange' },
];

<Combobox.Root aria-label="Favorite fruit">
  <Combobox.Label>Favorite fruit</Combobox.Label>
  <Combobox.Input placeholder="Search fruits…" clearable />
  <Combobox.Popover>
    <Combobox.ListBox items={options}>
      {(option) => (
        <Combobox.Item id={option.id} textValue={option.label}>
          {option.label}
        </Combobox.Item>
      )}
    </Combobox.ListBox>
  </Combobox.Popover>
</Combobox.Root>
```

```astro
---
// Filtering and listbox behavior require React — use the combobox recipe for static chrome.
import { combobox } from '@var-ui/core';

const cb = combobox();
---

<div class:list={[cb.root]}>
  <label class:list={[cb.label]} for="fruit-search">Favorite fruit</label>
  <div class:list={[cb.inputWrapper]}>
    <input
      class:list={[cb.input]}
      id="fruit-search"
      type="text"
      placeholder="Search fruits…"
      role="combobox"
      aria-autocomplete="list"
    />
  </div>
</div>
```

```html
<div class="var-ui-combobox"><label class="var-ui-combobox__label" for="fruit-search">Favorite fruit</label><div class="var-ui-combobox__inputWrapper"><input class="var-ui-combobox__input" id="fruit-search" type="text" placeholder="Search fruits…" role="combobox" aria-autocomplete="list" /></div></div>
```

### Field chrome

Add helper text and validation with `Description` and `Error`.

```tsx
import { Combobox } from '@var-ui/react';

const options = [
  { id: 'apple', label: 'Apple' },
  { id: 'plum', label: 'Plum' },
  { id: 'orange', label: 'Orange' },
];

<Combobox.Root aria-label="Favorite fruit" isInvalid>
  <Combobox.Label>Favorite fruit</Combobox.Label>
  <Combobox.Input placeholder="Search fruits…" clearable />
  <Combobox.Description>Pick a fruit from the list.</Combobox.Description>
  <Combobox.Error>Selection is required.</Combobox.Error>
  <Combobox.Popover>
    <Combobox.ListBox items={options}>
      {(option) => (
        <Combobox.Item id={option.id} textValue={option.label}>
          {option.label}
        </Combobox.Item>
      )}
    </Combobox.ListBox>
  </Combobox.Popover>
</Combobox.Root>
```

```astro
---
import { combobox } from '@var-ui/core';

const cb = combobox();
---

<div class:list={[cb.root]}>
  <label class:list={[cb.label]} for="fruit-field">Favorite fruit</label>
  <div class:list={[cb.inputWrapper]}>
    <input
      class:list={[cb.input]}
      id="fruit-field"
      type="text"
      placeholder="Search fruits…"
      role="combobox"
      aria-invalid="true"
    />
  </div>
  <p class:list={[cb.description]}>Pick a fruit from the list.</p>
  <p class:list={[cb.error]}>Selection is required.</p>
</div>
```

```html
<div class="var-ui-combobox"><label class="var-ui-combobox__label" for="fruit-field">Favorite fruit</label><div class="var-ui-combobox__inputWrapper"><input class="var-ui-combobox__input" id="fruit-field" type="text" placeholder="Search fruits…" role="combobox" aria-invalid="true" /></div><p class="var-ui-combobox__description">Pick a fruit from the list.</p><p class="var-ui-combobox__error">Selection is required.</p></div>
```

## Props

| Name | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| children | ReactNode | no |  |  |
| allowsEmptyCollection | boolean \| undefined | no |  | Whether the combo box allows the menu to be open when the collection is empty. |
| aria-describedby | string \| undefined | no |  | Identifies the element (or elements) that describes the object. |
| aria-details | string \| undefined | no |  | Identifies the element (or elements) that provide a detailed, extended description for the object. |
| aria-label | string \| undefined | no |  | Defines a string value that labels the current element. |
| aria-labelledby | string \| undefined | no |  | Identifies the element (or elements) that labels the current element. |
| autoFocus | boolean \| undefined | no |  | Whether the element should receive focus on render. |
| className | (ClassNameOrFunction<ComboBoxRenderProps> & string) \| undefined | no | 'react-aria-ComboBox' | The CSS [className](https://developer.mozilla.org/en-US/docs/Web/API/Element/className) for the element. A function may be provided to compute the class based on component state. |
| defaultFilter | ((textValue: string, inputValue: string) => boolean) \| undefined | no |  | The filter function used to determine if a option should be included in the combo box list. |
| defaultValue | Key \| null \| undefined | no |  | The default value (uncontrolled). |
| dir | string \| undefined | no |  |  |
| disabledKeys | Iterable<Key> \| undefined | no |  | The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. |
| form | string \| undefined | no |  | The `<form>` element to associate the input with. The value of this attribute must be the id of a `<form>` in the same document. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#form). |
| formValue | "text" \| "key" \| undefined | no | 'key' | Whether the text or key of the selected item is submitted as part of an HTML form. When `allowsCustomValue` is `true`, this option does not apply and the text is always submitted. |
| hidden | boolean \| undefined | no |  |  |
| id | string \| undefined | no |  | The element's unique identifier. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id). |
| inert | boolean \| undefined | no |  |  |
| isDisabled | boolean \| undefined | no |  | Whether the input is disabled. |
| isInvalid | boolean \| undefined | no |  | Whether the input value is invalid. |
| isReadOnly | boolean \| undefined | no |  | Whether the input can be selected but not changed by the user. |
| isRequired | boolean \| undefined | no |  | Whether user input is required on the input before form submission. |
| lang | string \| undefined | no |  |  |
| name | string \| undefined | no |  | The name of the input element, used when submitting an HTML form. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefname). |
| onAnimationEnd | AnimationEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onAnimationEndCapture | AnimationEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onAnimationIteration | AnimationEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onAnimationIterationCapture | AnimationEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onAnimationStart | AnimationEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onAnimationStartCapture | AnimationEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onAuxClick | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onAuxClickCapture | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onBlur | ((e: FocusEvent<HTMLInputElement, Element>) => void) \| undefined | no |  | Handler that is called when the element loses focus. |
| onChange | ((value: Key \| null) => void) \| undefined | no |  | Handler that is called when the value changes. |
| onClick | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onClickCapture | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onContextMenu | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onContextMenuCapture | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onDoubleClick | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onDoubleClickCapture | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onFocus | ((e: FocusEvent<HTMLInputElement, Element>) => void) \| undefined | no |  | Handler that is called when the element receives focus. |
| onFocusChange | ((isFocused: boolean) => void) \| undefined | no |  | Handler that is called when the element's focus status changes. |
| onGotPointerCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onGotPointerCaptureCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onKeyDown | ((e: KeyboardEvent) => void) \| undefined | no |  | Handler that is called when a key is pressed. |
| onKeyUp | ((e: KeyboardEvent) => void) \| undefined | no |  | Handler that is called when a key is released. |
| onLostPointerCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onLostPointerCaptureCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseDown | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseDownCapture | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseEnter | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseLeave | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseMove | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseMoveCapture | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseOut | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseOutCapture | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseOver | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseOverCapture | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseUp | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onMouseUpCapture | MouseEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerCancel | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerCancelCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerDown | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerDownCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerEnter | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerLeave | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerMove | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerMoveCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerOut | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerOutCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerOver | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerOverCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerUp | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onPointerUpCapture | PointerEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onScroll | UIEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onScrollCapture | UIEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTouchCancel | TouchEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTouchCancelCapture | TouchEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTouchEnd | TouchEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTouchEndCapture | TouchEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTouchMove | TouchEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTouchMoveCapture | TouchEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTouchStart | TouchEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTouchStartCapture | TouchEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTransitionCancel | TransitionEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTransitionCancelCapture | TransitionEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTransitionEnd | TransitionEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTransitionEndCapture | TransitionEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTransitionRun | TransitionEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTransitionRunCapture | TransitionEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTransitionStart | TransitionEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onTransitionStartCapture | TransitionEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onWheel | WheelEventHandler<HTMLDivElement> \| undefined | no |  |  |
| onWheelCapture | WheelEventHandler<HTMLDivElement> \| undefined | no |  |  |
| render | DOMRenderFunction<"div", ComboBoxRenderProps> \| undefined | no |  | Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components.  Requirements:  - You must render the expected element type (e.g. if `<button>` is expected, you cannot render an   `<a>`). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop   as appropriate. |
| shouldFocusWrap | boolean \| undefined | no |  | Whether keyboard navigation is circular. |
| slot | string \| null \| undefined | no |  | A slot name for the component. Slots allow the component to receive props from a parent component. An explicit `null` value indicates that the local props completely override all props received from a parent. |
| style | StyleOrFunction<ComboBoxRenderProps> \| undefined | no |  | The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state. |
| translate | "yes" \| "no" \| undefined | no |  |  |
| validate | ((value: ComboBoxValidationValue<"single">) => true \| ValidationError \| null \| undefined) \| undefined | no |  | A function that returns an error message if a given value is invalid. Validation errors are displayed to the user when the form is submitted if `validationBehavior="native"`. For realtime validation, use the `isInvalid` prop instead. |
| validationBehavior | "native" \| "aria" \| undefined | no | 'native' | Whether to use native HTML form validation to prevent form submission when the value is missing or invalid, or mark the field as required or invalid via ARIA. |
| value | Key \| null \| undefined | no |  | The current value (controlled). |
| allowsCustomValue | boolean \| undefined | no |  | Whether the ComboBox allows a non-item matching input value to be set. |
| defaultInputValue | string \| undefined | no |  | The default value of the ComboBox input (uncontrolled). |
| defaultItems | Iterable<T> \| undefined | no |  | The list of ComboBox items (uncontrolled). |
| defaultSelectedKey | Key \| null \| undefined | no |  | The initial selected key in the collection (uncontrolled). |
| inputValue | string \| undefined | no |  | The value of the ComboBox input (controlled). |
| items | Iterable<T> \| undefined | no |  | The list of ComboBox items (controlled). |
| menuTrigger | MenuTriggerAction \| undefined | no | 'input' | The interaction required to display the ComboBox menu. |
| onInputChange | ((value: string) => void) \| undefined | no |  | Handler that is called when the ComboBox input value changes. |
| onOpenChange | ((isOpen: boolean, menuTrigger?: MenuTriggerAction \| undefined) => void) \| undefined | no |  | Method that is called when the open state of the menu changes. Returns the new open state and the action that caused the opening of the menu. |
| onSelectionChange | ((key: Key \| null) => void) \| undefined | no |  | Handler that is called when the selection changes. |
| selectedKey | Key \| null \| undefined | no |  | The currently selected key in the collection (controlled). |
| selectionMode | "single" \| undefined | no | 'single' | Whether single or multiple selection is enabled. |

## Accessibility

Built on React Aria Components. The input exposes `role="combobox"`; the listbox opens
on focus or typing and supports keyboard navigation.
