Design guidance

ComboBox is the right choice when your list has many options (more than ~7) and you want to help users narrow options via text. For shorter, fixed lists, consider Select instead.

When to use ComboBox vs Select

SituationRecommendation
Short list (<7 items), no typing neededUse Select
Long list, users filter by typingUse ComboBox
Free-form text + suggestionsUse ComboBox with allowsCustomValue
Async search (server-side filtering)Use ComboBox with onInputChange

Anatomy

  • Label — always visible above the field (never placeholder-only).
  • Input — text field where the user types.
  • Dropdown button — chevron that opens/closes the listbox.
  • Listbox — filtered options rendered in a popover.
  • Description / error text — below the field for help and validation.

Basic ComboBox (S2)

import {ComboBox, Item} from '@react-spectrum/s2';

<ComboBox label="Component">
  <Item>Button</Item>
  <Item>ComboBox</Item>
  <Item>TextField</Item>
</ComboBox>

Controlled with async loading

import {ComboBox, Item} from '@react-spectrum/s2';
import {useAsyncList} from 'react-stately';

function AsyncComboBox() {
  const list = useAsyncList({
    async load({signal, filterText}) {
      const res = await fetch(
        `/api/search?q=${filterText}`,
        {signal}
      );
      const json = await res.json();
      return {items: json.results};
    },
  });

  return (
    <ComboBox
      label="Search"
      items={list.items}
      inputValue={list.filterText}
      onInputChange={list.setFilterText}
      loadingState={list.loadingState}
      onLoadMore={list.loadMore}>
      {(item) => <Item key={item.id}>{item.name}</Item>}
    </ComboBox>
  );
}

Key props — ComboBox (S2)

PropTypeDescription
labelReactNodeAlways provide a label for accessibility.
inputValuestringControlled text input value.
selectedKeyKeyControlled selected item key.
onInputChange(value: string) => voidFires on every keystroke.
onSelectionChange(key: Key) => voidFires when user picks an option.
allowsCustomValuebooleanAllows free-form text not in the list.
loadingState'loading' | 'loadingMore' | 'idle' | …Shows spinner in appropriate state.
isDisabledbooleanDisables the combobox.