A combo box combines a text input with a listbox, allowing users to filter a list of options to items matching a query.
Vanilla CSS theme
--tint CSS variable used by the Vanilla CSS examples.Content
ComboBox reuses the ListBox component, following the Collection Components API. It supports ListBox features such as static and dynamic collections, sections, disabled items, links, text slots, asynchronous loading, etc. See the ListBox docs for more details.
The following example shows a dynamic collection of items, grouped into sections.
import {ComboBox, ComboBoxItem} from './ComboBox';
import {ListBoxSection, Collection, Header} from 'react-aria-components';
function Example() {
return (
<ComboBox
label="Preferred fruit or vegetable"
placeholder="Select an option"
defaultItems={options}>
{section => (
<ListBoxSection id={section.name}>
<Header>{section.name}</Header>
<Collection items={section.children}>
{item => <ComboBoxItem id={item.name}>{item.name}</ComboBoxItem>}
</Collection>
</ListBoxSection>
)}
</ComboBox>
);
}
TagGroup
Use the ComboBoxValue render prop function to display the selected items as a TagGroup.
import {ComboBox, ComboBoxValue, Input} from 'react-aria-components';
import {ComboBoxListBox, ComboBoxItem} from './ComboBox';
import {Label, FieldButton} from './Form';
import {Popover} from './Popover';
import {Tag, TagGroup} from './TagGroup';
import {ChevronDown} from 'lucide-react';
<ComboBox selectionMode="multiple">
<Label>States</Label>
<div className="combobox-field">
<Input className="react-aria-Input inset" placeholder="Select a state" />
<FieldButton><ChevronDown /></FieldButton>
</div>
<ComboBoxValue<typeof states[0]>>
{({selectedItems, state}) => (
<TagGroup
aria-label="Selected states"
style={{marginTop: 8}}
items={selectedItems.filter(item => item != null)}
renderEmptyState={() => 'No selected items'}
onRemove={(keys) => {
// Remove keys from ComboBox state.
if (Array.isArray(state.value)) {
state.setValue(state.value.filter(k => !keys.has(k)));
}
}}>
{item => <Tag>{item.name}</Tag>}
</TagGroup>
)}
</ComboBoxValue>
<Popover hideArrow className="combobox-popover">
<ComboBoxListBox items={states}>
{state => <ComboBoxItem>{state.name}</ComboBoxItem>}
</ComboBoxListBox>
</Popover>
</ComboBox>
Value
Use the defaultValue or value prop to set the selected item. The value corresponds to the id prop of an item. Items can be disabled with the isDisabled prop.
Current selection: bison
import {ComboBox, ComboBoxItem} from './ComboBox';
import {useState} from 'react';
import type {Key} from 'react-aria-components';
function Example() {
let [animal, setAnimal] = useState<Key | null>("bison");
return (
<div>
<ComboBox
label="Favorite Animal"
placeholder="Select an animal"
value={animal}
onChange={setAnimal}>
<ComboBoxItem id="koala">Koala</ComboBoxItem>
<ComboBoxItem id="kangaroo">Kangaroo</ComboBoxItem>
<ComboBoxItem id="platypus" isDisabled>Platypus</ComboBoxItem>
<ComboBoxItem id="eagle">Bald Eagle</ComboBoxItem>
<ComboBoxItem id="bison">Bison</ComboBoxItem>
<ComboBoxItem id="skunk">Skunk</ComboBoxItem>
</ComboBox>
<p>Current selection: {animal}</p>
</div>
);
}
Input value
Use the inputValue or defaultInputValue prop to set the value of the input field. By default, the value will be reverted to the selected item on blur. Set the allowsCustomValue prop to enable entering values that are not in the list.
Current input value: Kangaroo
Fully controlled
Both inputValue and value can be controlled simultaneously. However, each interaction will only trigger either onInputChange or onChange, not both. When controlling both props, you must update both values accordingly.
Current selected major id: Current input text:
import type {Key} from 'react-aria-components';
import {ComboBox, ComboBoxItem} from './ComboBox';
import {useState} from 'react';
function ControlledComboBox() {
let [fieldState, setFieldState] = useState<{value: Key | null, inputValue: string}>({
value: null,
inputValue: ''
});
let onChange = (id: Key | null) => {
// Update inputValue when value changes.
setFieldState({
inputValue: id == null ? '' : options.find(o => o.id === id)?.name ?? '',
value: id
});
};
let onInputChange = (value: string) => {
// Reset value to null if the input is cleared.
setFieldState(prevState => ({
inputValue: value,
value: value === '' ? null : prevState.value
}));
};
return (
<div>
<ComboBox
label="Engineering major"
placeholder="Select a major"
defaultItems={options}
value={fieldState.value}
inputValue={fieldState.inputValue}
onChange={onChange}
onInputChange={onInputChange}>
{item => <ComboBoxItem>{item.name}</ComboBoxItem>}
</ComboBox>
<pre style={{fontSize: 12}}>
Current selected major id: {fieldState.value}{'\n'}
Current input text: {fieldState.inputValue}
</pre>
</div>
);
}
Item actions
Use the onAction prop on a <ListBoxItem> to perform a custom action when the item is pressed. This example adds a "Create" action for the current input value.
import {ComboBox, ComboBoxItem} from './ComboBox';
import {useState} from 'react';
function Example() {
let [inputValue, setInputValue] = useState('');
return (
<ComboBox
label="Favorite Animal"
placeholder="Select an animal"
allowsEmptyCollection
inputValue={inputValue}
onInputChange={setInputValue}>
{inputValue.length > 0 && (
<ComboBoxItem onAction={() => alert('Creating ' + inputValue)}>
{`Create "${inputValue}"`}
</ComboBoxItem>
)}
<ComboBoxItem>Aardvark</ComboBoxItem>
<ComboBoxItem>Cat</ComboBoxItem>
<ComboBoxItem>Dog</ComboBoxItem>
<ComboBoxItem>Kangaroo</ComboBoxItem>
<ComboBoxItem>Panda</ComboBoxItem>
<ComboBoxItem>Snake</ComboBoxItem>
</ComboBox>
);
}
Forms
Use the name prop to submit the id of the selected item to the server. Set the isRequired prop to validate that the user selects a value, or implement custom client or server-side validation. See the Forms guide to learn more.
import {ComboBox, ComboBoxItem} from './ComboBox';
import {Button} from './Button';
import {Form} from './Form';;
<Form>
<ComboBox
label="Animal"
placeholder="e.g. Cat"
name="animal"
isRequired
description="Please select an animal.">
<ComboBoxItem id="aardvark">Aardvark</ComboBoxItem>
<ComboBoxItem id="cat">Cat</ComboBoxItem>
<ComboBoxItem id="dog">Dog</ComboBoxItem>
<ComboBoxItem id="kangaroo">Kangaroo</ComboBoxItem>
<ComboBoxItem id="panda">Panda</ComboBoxItem>
<ComboBoxItem id="snake">Snake</ComboBoxItem>
</ComboBox>
<Button type="submit">Submit</Button>
</Form>
Popover
Use the menuTrigger prop to control when the popover opens:
input(default): popover opens when the user edits the input text.focus: popover opens when the user focuses the input.manual: popover only opens when the user presses the trigger button or uses the arrow keys.
Use allowsEmptyCollection to keep the popover open when there are no items available in the list.
API
<ComboBox>
<Label />
<Input />
<Button />
<ComboBoxValue />
<Text slot="description" />
<FieldError />
<Popover>
<ListBox />
</Popover>
</ComboBox>
ComboBox
| Name | Type | Default |
|---|---|---|
defaultFilter | | Default: — |
The filter function used to determine if a option should be included in the combo box list. | ||
allowsEmptyCollection | boolean | Default: — |
Whether the combo box allows the menu to be open when the collection is empty. | ||
allowsCustomValue | boolean | Default: — |
Whether the ComboBox allows a non-item matching input value to be set. | ||
menuTrigger | MenuTriggerAction | Default: 'input'
|
The interaction required to display the ComboBox menu. | ||
isDisabled | boolean | Default: — |
Whether the input is disabled. | ||
isReadOnly | boolean | Default: — |
Whether the input can be selected but not changed by the user. | ||
children | ChildrenOrFunction | Default: — |
The children of the component. A function may be provided to alter the children based on component state. | ||
items | Iterable | Default: — |
The list of ComboBox items (controlled). | ||
defaultItems | Iterable | Default: — |
The list of ComboBox items (uncontrolled). | ||
selectionMode | SelectionMode | Default: 'single'
|
Whether single or multiple selection is enabled. | ||
disabledKeys | Iterable | Default: — |
The item keys that are disabled. These items cannot be selected, focused, or otherwise interacted with. | ||
shouldFocusWrap | boolean | Default: — |
Whether keyboard navigation is circular. | ||
value | ValueType | Default: — |
The current value (controlled). | ||
defaultValue | ValueType | Default: — |
The default value (uncontrolled). | ||
onChange | | Default: — |
Handler that is called when the value changes. | ||
inputValue | string | Default: — |
The value of the ComboBox input (controlled). | ||
defaultInputValue | string | Default: — |
The default value of the ComboBox input (uncontrolled). | ||
onInputChange | | Default: — |
Handler that is called when the ComboBox input value changes. | ||
Default className: react-aria-ComboBox
| Render Prop | CSS Selector |
|---|---|
isOpen | CSS Selector: [data-open]
|
| Whether the combobox is currently open. | |
isDisabled | CSS Selector: [data-disabled]
|
| Whether the combobox is disabled. | |
isInvalid | CSS Selector: [data-invalid]
|
| Whether the combobox is invalid. | |
isRequired | CSS Selector: [data-required]
|
| Whether the combobox is required. | |
ComboBoxValue
ComboBoxValue renders the selected values of a ComboBox, or a placeholder if no value is selected. By default, the items are rendered as a comma separated list. Use the render function to customize this.
| Name | Type | |
|---|---|---|
placeholder | ReactNode | |
A value to display when no items are selected. | ||
children | ChildrenOrFunction | |
The children of the component. A function may be provided to alter the children based on component state. | ||
Default className: react-aria-ComboBoxValue