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
Dropdown variant
Autocomplete variant
<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
Click dropdown arrow to view loading state...
<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
Start typing 'test' to see no results state...
<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
Please select a country
<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
A selection is required
<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

childrenReactNode & CollectionChildren<object>The contents of the collection.

containerRef?RefObject<HTMLElement>The ref of the element to append the overlay to.

helperText?ReactNodeHelper text to append to the form control input element.

helperTextProps?HTMLAttributes<HTMLElement>Props passed to the helper text.

label?ReactNodeLabel of the input element

labelProps?HTMLAttributes<HTMLElement>Props passed to the label.

maxHeight?numberThe maxHeight specified for the overlay element. By default, it will take all space up to the current viewport height.

offset?numberThe additional offset applied along the main axis between the element and its anchor element.Defaults to 4

placement?PlacementThe placement of the element with respect to its anchor element.Defaults to 'bottom'

shouldFlip?booleanWhether the element should flip its orientation (e.g. top to bottom or left to right) when there is insufficient room for it to render completely.Defaults to true

size?"small" | "medium"The size of the comboboxDefaults to 'medium'

startIcon?ReactElement<any, string | JSXElementConstructor<any>>Icon displayed at the start of the combobox.

variant?"autocomplete" | "dropdown"Combobox variant

loading?booleanSpecifies if the component is in a loading state

loadingText?stringSpecifies the loading state content for the combobox. If not provided no text will be displayed in the loading state

noResultsChildren?ReactElement<any, string | JSXElementConstructor<any>> | ReactElement<any, string | JSXElementConstructor<any>>[]Specifies the no results ui elements for the combobox

as?NonNullable<T>

css?CSSTheme aware style object.

ComboboxItem Props


as?The root element to be rendered

as?"div"

css?CSSTheme aware style object.

startIcon?ReactElement<any, string | JSXElementConstructor<any>>Icon added before the item text.

ComboboxSection Props


as?The root element to be rendered

as?"div"

childrenReactNode & (ItemElement<object> | ItemElement<object>[] | ItemRenderer<object>)Static child items or a function to render children.

css?CSSTheme aware style object.