ComboBox
ComboBox allow users to choose a single option from a collapsible list of options when space is limited.
Content
ComboBox
follows the Collection Components API, accepting both static and dynamic collections. This example shows a dynamic collection, passing a list of objects to the items
prop, and a function to render the children.
import {ComboBox, ComboBoxItem} from '@react-spectrum/s2';
function Example() {
let options = [
{ id: 1, name: 'Aardvark' },
{ id: 2, name: 'Cat' },
{ id: 3, name: 'Dog' },
{ id: 4, name: 'Kangaroo' },
{ id: 5, name: 'Koala' },
{ id: 6, name: 'Penguin' },
{ id: 7, name: 'Snake' },
{ id: 8, name: 'Turtle' },
{ id: 9, name: 'Wombat' }
];
return (
<ComboBox label="Animals" items={options} selectionMode="single">
{(item) => <ComboBoxItem>{item.name}</ComboBoxItem>}
</ComboBox>
);
}
Slots
ComboBoxItem
supports icons, and label
and description
text slots.
import {ComboBox, ComboBoxItem, Text} from '@react-spectrum/s2';
import Comment from '@react-spectrum/s2/icons/Comment';
import Edit from '@react-spectrum/s2/icons/Edit';
import UserSettings from '@react-spectrum/s2/icons/UserSettings';
<ComboBox label="Permissions" defaultSelectedKey="read">
<ComboBoxItem id="read" textValue="Read">
<Comment />
<Text slot="label">Read</Text>
<Text slot="description">Comment only</Text>
</ComboBoxItem>
<ComboBoxItem id="write" textValue="Write">
<Edit />
<Text slot="label">Write</Text>
<Text slot="description">Read and write only</Text>
</ComboBoxItem>
<ComboBoxItem id="admin" textValue="Admin">
<UserSettings />
<Text slot="label">Admin</Text>
<Text slot="description">Full access</Text>
</ComboBoxItem>
</ComboBox>
Sections
Use the <ComboBoxSection>
component to group options. A <Header>
element, with a <Heading>
and optional description
slot can be included to label a section. Sections without a header must have an aria-label
.
import {ComboBox, ComboBoxItem, ComboBoxSection, Header, Heading, Text} from '@react-spectrum/s2';
<ComboBox label="Preferred fruit or vegetable">
<ComboBoxSection>
<Header>
<Heading>Fruit</Heading>
<Text slot="description">Sweet and nutritious</Text>
</Header>
<ComboBoxItem id="apple">Apple</ComboBoxItem>
<ComboBoxItem id="banana">Banana</ComboBoxItem>
<ComboBoxItem id="orange">Orange</ComboBoxItem>
<ComboBoxItem id="grapes">Grapes</ComboBoxItem>
</ComboBoxSection>
<ComboBoxSection>
<Header>
<Heading>Vegetable</Heading>
<Text slot="description">Healthy and savory</Text>
</Header>
<ComboBoxItem id="broccoli">Broccoli</ComboBoxItem>
<ComboBoxItem id="carrots">Carrots</ComboBoxItem>
<ComboBoxItem id="spinach">Spinach</ComboBoxItem>
<ComboBoxItem id="lettuce">Lettuce</ComboBoxItem>
</ComboBoxSection>
</ComboBox>
Asynchronous loading
Use the loadingState
and onLoadMore
props to enable async loading and infinite scrolling.
import {ComboBox, ComboBoxItem} from '@react-spectrum/s2';
import {useAsyncList} from 'react-stately';
function Example() {
let list = useAsyncList({
async load({signal, cursor, filterText}) {
if (cursor) {
cursor = cursor.replace(/^http:\/\//i, 'https://');
}
let res = await fetch(cursor || `https://swapi.py4e.com/api/people/?search=${filterText}`, {signal});
let json = await res.json();
return {
items: json.results,
cursor: json.next
};
}
});
return (
<ComboBox
label="Star Wars Character Lookup"
items={list.items}
inputValue={list.filterText}
onInputChange={list.setFilterText}
loadingState={list.loadingState}
onLoadMore={list.loadMore}>
{item => <ComboBoxItem id={item.name} textValue={item.name}>{item.name}</ComboBoxItem>}
</ComboBox>
);
}
Links
Use the href
prop on a <ComboBoxItem>
to create a link. See the client side routing guide to learn how to integrate with your framework. Link items in a ComboBox
are not selectable.
import {ComboBox, ComboBoxItem} from '@react-spectrum/s2';
<ComboBox label="Bookmarks">
<ComboBoxItem href="https://adobe.com/" target="_blank">Adobe</ComboBoxItem>
<ComboBoxItem href="https://apple.com/" target="_blank">Apple</ComboBoxItem>
<ComboBoxItem href="https://google.com/" target="_blank">Google</ComboBoxItem>
<ComboBoxItem href="https://microsoft.com/" target="_blank">Microsoft</ComboBoxItem>
</ComboBox>
Selection
Use the defaultSelectedKey
or selectedKey
prop to set the selected item. The selected key corresponds to the id
prop of an item. Items can be disabled with the isDisabled
prop. See the selection guide for more details.
Current selection: bison
import {ComboBox, ComboBoxItem, type Key} from '@react-spectrum/s2';
import {useState} from 'react';
function Example() {
let [animal, setAnimal] = useState<Key>("bison");
return (
<div>
<ComboBox
label="Pick an animal"
selectedKey={animal}
onSelectionChange={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 selectedKey
can be controlled simultaneously. However, each interaction will only trigger either onInputChange
or onSelectionChange
, not both. When controlling both props, you must update both values accordingly.
Current selected major id: Current input text:
import {ComboBox, ComboBoxItem, type Key} from '@react-spectrum/s2';
import {useState} from 'react';
function ControlledComboBox() {
let [fieldState, setFieldState] = useState({
selectedKey: null,
inputValue: ''
});
let onSelectionChange = (id: Key) => {
// Update inputValue when selectedKey changes.
setFieldState({
inputValue: options.find(o => o.id === id)?.name ?? '',
selectedKey: id
});
};
let onInputChange = (value: string) => {
// Reset selectedKey to null if the input is cleared.
setFieldState(prevState => ({
inputValue: value,
selectedKey: value === '' ? null : prevState.selectedKey
}));
};
return (
<div>
<ComboBox
label="Pick a engineering major"
defaultItems={options}
selectedKey={fieldState.selectedKey}
inputValue={fieldState.inputValue}
onSelectionChange={onSelectionChange}
onInputChange={onInputChange}>
{item => <ComboBoxItem>{item.name}</ComboBoxItem>}
</ComboBox>
<pre style={{fontSize: 12}}>
Current selected major id: {fieldState.selectedKey}{'\n'}
Current input text: {fieldState.inputValue}
</pre>
</div>
);
}
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.
Popover options
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.
The align
, direction
, shouldFlip
and menuWidth
props control the behavior of the popover.
API
<ComboBox>
<ComboBoxItem>
<Icon />
<Text slot="label" />
<Text slot="description" />
</ComboBoxItem>
<ComboBoxSection>
<Header>
<Heading />
<Text slot="description" />
</Header>
<ComboBoxItem />
</ComboBoxSection>
</ComboBox>
ComboBox
Name | Type | Default |
---|---|---|
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. | ||
size | 'S'
| 'M'
| 'L'
| 'XL' | Default: 'M'
|
The size of the Combobox. | ||
styles | StylesProp | Default: — |
Spectrum-defined styles, returned by the style() macro. | ||
children | ReactNode | | Default: — |
The contents of the collection. | ||
items | Iterable | Default: — |
The list of ComboBox items (controlled). | ||
defaultItems | Iterable | Default: — |
The list of ComboBox items (uncontrolled). | ||
loadingState | LoadingState | Default: — |
The current loading state of the ComboBox. Determines whether or not the progress circle should be shown. | ||
onLoadMore |
| Default: — |
Handler that is called when more items should be loaded, e.g. while scrolling near the bottom. | ||
dependencies | ReadonlyArray | Default: — |
Values that should invalidate the item cache when using dynamic collections. | ||
selectedKey | Key | null | Default: — |
The currently selected key in the collection (controlled). | ||
defaultSelectedKey | Key | Default: — |
The initial selected key in the collection (uncontrolled). | ||
onSelectionChange |
| Default: — |
Handler that is called when the selection changes. | ||
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. | ||
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. | ||
ComboBoxItem
Name | Type | |
---|---|---|
children | ReactNode | |
id | Key | |
The unique id of the item. | ||
value | T | |
The object value that this item represents. When using dynamic collections, this is set automatically. | ||
textValue | string | |
A string representation of the item's contents, used for features like typeahead. | ||
isDisabled | boolean | |
Whether the item is disabled. | ||
styles | StylesProp | |
Spectrum-defined styles, returned by the style() macro. | ||
ComboBoxSection
Name | Type | |
---|---|---|
id | Key | |
The unique id of the section. | ||
value | T | |
The object value that this section represents. When using dynamic collections, this is set automatically. | ||
children | ReactNode | | |
Static child items or a function to render children. | ||
items | Iterable | |
Item objects in the section. | ||
dependencies | ReadonlyArray | |
Values that should invalidate the item cache when using dynamic collections. | ||