Skip to main content

Combobox

An autocomplete input that allows a user to filter a list of selectable options.

http://localhost:3000
<Combobox aria-label="Country Select">
  <ComboboxItem>United States</ComboboxItem>
  <ComboboxItem>Canada</ComboboxItem>
  <ComboboxItem>Mexico</ComboboxItem>
</Combobox>

Usage

Selection

Setting a selected option can be done by using the defaultSelectedKey or selectedKey prop

http://localhost:3000
function Selection() {
  const options = [
    { id: 1, name: 'United States' },
    { id: 2, name: 'Canada' },
    { id: 3, name: 'Mexico' },
    { id: 4, name: 'United Kingdom' },
    { id: 5, name: 'France' },
    { id: 6, name: 'China' },
    { id: 7, name: 'India' },
    { id: 8, name: 'Turkey' },
  ];

  const [selected, setSelected] = React.useState('Turkey');

  return (
    <Combobox aria-label="Country Select" selectedKey={selected} onSelectionChange={setSelected}>
      {options.map((item) => (
        <ComboboxItem key={item.name}>{item.name}</ComboboxItem>
      ))}
    </Combobox>
  );
}

Sections

Group items within a dropdown using a section.

http://localhost:3000
<Combobox aria-label="Country Select">
  <ComboboxSection title="North America">
    <ComboboxItem>United States</ComboboxItem>
    <ComboboxItem>Canada</ComboboxItem>
    <ComboboxItem>Mexico</ComboboxItem>
  </ComboboxSection>
  <ComboboxSection title="Europe">
    <ComboboxItem>United Kingdom</ComboboxItem>
    <ComboboxItem>France</ComboboxItem>
  </ComboboxSection>
  <ComboboxSection title="Asia">
    <ComboboxItem>China</ComboboxItem>
    <ComboboxItem>India</ComboboxItem>
  </ComboboxSection>
</Combobox>

Variant

Combobox has two variant, dropdown and autocomplete. The main difference between the two is that the dropdown variant renders a dropdown button next to the input.

http://localhost:3000
<Flex gap="small">
<Combobox variant="dropdown" helperText="Dropdown variant">
  <ComboboxItem>United States</ComboboxItem>
  <ComboboxItem>Canada</ComboboxItem>
  <ComboboxItem>Mexico</ComboboxItem>
</Combobox>
<Combobox variant="autocomplete" helperText="Autocomplete variant">
  <ComboboxItem>United States</ComboboxItem>
  <ComboboxItem>Canada</ComboboxItem>
  <ComboboxItem>Mexico</ComboboxItem>
</Combobox>
</div>

Loading state

Combobox gives you the control over what text should be rendered in a loading state

http://localhost:3000
<Combobox 
    loading 
    loadingText="Loading state text goes here..." 
    helperText="Click dropdown arrow to view loading state...">
      <ComboboxItem key="ardvark">Ardvark</ComboboxItem>
      <ComboboxItem key="kangaroo">Kangaroo</ComboboxItem>
      <ComboboxItem key="snake">Snake</ComboboxItem>
    </Combobox>

No results state

http://localhost:3000
<Combobox
      helperText="Start typing 'test' to see no results state..."
      noResultsChildren={
        <Flex justify="center">
          <Typography variant="caption" css={{ color: '$text-secondary' }}>
            No results state goes here...
          </Typography>
        </Flex>
      }
    >
  <ComboboxItem key="ardvark">Ardvark</ComboboxItem>
</Combobox>

Async

Items can be loaded asynchronously use the useAsyncData hook. It also supports infinite scrolling to load more data on demand as the user scrolls, via the onLoadMore prop.

http://localhost:3000
function Async() {
    const list = useAsyncList({
      async load({ signal, filterText }) {
        const res = await fetch(`https://restcountries.com/v3.1/name/${filterText}`, {
          signal,
        });

        if (res.status !== 200) return { items: [] };
        const items = await res.json()
        return {
          items: items.map((x) => ({
            value: x.name.common,
          })),
        };
      },
    });

    const handleInputChanged = React.useCallback(
      (value) => list.setFilterText(value),
      [list],
    );

    return (
      <Combobox
        aria-label="test"
        inputValue={list.filterText}
        items={list.items}
        loading={list.isLoading}
        loadingText="Searching an free list of countries..."
        noResultsChildren={<Flex justify="center"><Typography variant="caption">😭 No results found</Typography></Flex>}
        onInputChange={handleInputChanged}
        variant="autocomplete"
        placeholder="Start typing to search for a country..."
      >
        {(item) => (
          <ComboboxItem key={item.value}>{item.value}</ComboboxItem>
        )}
      </Combobox>
    );
}

Label

Attach a label to the combobox using the label prop.

http://localhost:3000
<Combobox label="Country">
  <ComboboxItem>United States</ComboboxItem>
  <ComboboxItem>Canada</ComboboxItem>
  <ComboboxItem>Mexico</ComboboxItem>
</Combobox>

HelperText

Add additional context as well as display error messages with the helperText prop.

http://localhost:3000
<Combobox label="Country" helperText="Please select a country">
  <ComboboxItem>United States</ComboboxItem>
  <ComboboxItem>Canada</ComboboxItem>
  <ComboboxItem>Mexico</ComboboxItem>
</Combobox>

Small

A small combobox is used when vertical spacing is limited.

http://localhost:3000
<Combobox aria-label="Country Select" size="small">
  <ComboboxItem>United States</ComboboxItem>
  <ComboboxItem>Canada</ComboboxItem>
  <ComboboxItem>Mexico</ComboboxItem>
</Combobox>

Start Icon

Include an icon before the input text.

http://localhost:3000
<Combobox aria-label="status" startIcon={<Search />}>
  <ComboboxItem>United States</ComboboxItem>
  <ComboboxItem>Canada</ComboboxItem>
  <ComboboxItem>Mexico</ComboboxItem>
</Combobox>

Item Icon

Include an icon before the item label on each item.

http://localhost:3000
<Combobox aria-label="status">
  <ComboboxItem startIcon={<Truck />}>Truck</ComboboxItem>
  <ComboboxItem startIcon={<Train />}>Train</ComboboxItem>
  <ComboboxItem startIcon={<Airplane />}>Airplane</ComboboxItem>
  <ComboboxItem startIcon={<Boat />}>Ship</ComboboxItem>
</Combobox>

Controlled

A combobox's state can be fully controlled including both the text input and item selection.

http://localhost:3000
function ControlledExample() {
  const data = [
    { id: 1, name: 'United States' },
    { id: 2, name: 'Canada' },
    { id: 3, name: 'Mexico' },
    { id: 4, name: 'United Kingdom' },
    { id: 5, name: 'France' },
    { id: 6, name: 'China' },
    { id: 7, name: 'India' },
    { id: 8, name: 'Turkey' },
  ];

  const list = useTreeData({ initialItems: data });

  const [state, dispatch] = React.useReducer(
    (state, action) => {
      switch (action.type) {
        case 'INPUT_CHANGE':
          return {
            inputValue: action.payload,
            selectedId: action.payload === '' ? null : state.selectedId,
          };
        case 'SELECTION_CHANGE':
          return {
            inputValue: action.payload ? list.getItem(action.payload).value.name : '',
            selectedKey: action.payload,
          };
        default:
          throw new Error();
      }
    },
    { inputValue: '', selectedKey: null },
  );

  return (
    <Combobox
      aria-label="status"
      defaultItems={list.items}
      inputValue={state.inputValue}
      onInputChange={(value) => dispatch({ type: 'INPUT_CHANGE', payload: value })}
      onSelectionChange={(key) => dispatch({ type: 'SELECTION_CHANGE', payload: key })}
      selectedKey={state.selectedKey}
    >
      {(item) => <ComboboxItem>{item.value.name}</ComboboxItem>}
    </Combobox>
  );
}

Disabled State

Set the isDisabled prop to prevent a user from interacting with the combobox.

http://localhost:3000
<Combobox aria-label="status" isDisabled>
  <SelectItem>United States</SelectItem>
  <SelectItem>Canada</SelectItem>
  <SelectItem>Mexico</SelectItem>
</Combobox>

Disabled items

Set the disabledKeys prop to disable certain items in the combobox list.

http://localhost:3000
<Combobox aria-label="status" disabledKeys={['canada']}>
  <ComboboxItem key="united_states">United States</ComboboxItem>
  <ComboboxItem key="canada">Canada</ComboboxItem>
  <ComboboxItem key="mexico">Mexico</ComboboxItem>
</Combobox>

Invalid State

Set the validationState prop to invalid to render the combobox in an invalid state.

http://localhost:3000
<Combobox aria-label="status" helperText="A selection is required" validationState="invalid">
  <ComboboxItem>United States</ComboboxItem>
  <ComboboxItem>Canada</ComboboxItem>
  <ComboboxItem>Mexico</ComboboxItem>
</Combobox>

Props

Combobox Props


as?The root element to be rendered

ComboboxItem Props


as?The root element to be rendered

ComboboxSection Props


as?The root element to be rendered