> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Combobox - Web

> Comboboxes are form elements that allow users to filter and select a value from a list.

> [!NOTE]
>
> For development, import `Combobox` from
> `@servicetitan/anvil2`. For design, find it in the
> [Anvil2 file](https://www.figma.com/design/xaNQsvRKczoxu7pj0M6QT8/Anvil2-v3).

> [!WARNING]
>
> Combobox is deprecated. Use [SelectField](https://anvil.servicetitan.com/docs/components/select-field/code) for single selection or [MultiSelectField](https://anvil.servicetitan.com/docs/components/multi-select-field/code) for multiple selection. Combobox will be removed in Anvil2 5.0.

![](https://mintcdn.com/servicetitan/uz2PQSvO75TRhQ38/images/docs/web/components/shared/combobox-overview.png?fit=max\&auto=format\&n=uz2PQSvO75TRhQ38\&q=85\&s=076dcb8d04a6accaecba39bb4921d5d0)

## Anatomy

The Combobox consists of four primary elements that work together to allow users to filter and select values from a list.

![Combobox
anatomy](https://mintcdn.com/servicetitan/Ni0bXIw9diilEZPZ/images/docs/web/components/combobox/design/combobox-anatomy.png?fit=max\&auto=format\&n=Ni0bXIw9diilEZPZ\&q=85\&s=a89253fc48c1f420fc6e865bb8992db2)

1. Trigger
2. Content
3. Clear button (Optional)
4. Popover

## Options

The Combobox supports single and multi-select configurations to accommodate various selection scenarios.

combobox-multiple-false

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-multiple-false?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Casey Maxwell" },
  { id: 2, name: "Giovanni Saunders" },
  { id: 3, name: "Harper Gonzalez" },
  { id: 4, name: "Jane Doe" },
  { id: 5, name: "Meadow Hunter" },
];

function App() {
  const [, setSelected] = useState<Item | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        defaultIsOpen
      >
        <Combobox.SearchField label="Select Teammate" />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

### Multi Select

combobox-multiple

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-multiple?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Casey Maxwell" },
  { id: 2, name: "Giovanni Saunders" },
  { id: 3, name: "Harper Gonzalez" },
  { id: 4, name: "Jane Doe" },
  { id: 5, name: "Meadow Hunter" },
];

function App() {
  const [, setSelected] = useState<Item[] | null>([]);

  return (
    <div style={{ minWidth: "384px", minHeight: "300px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        multiple
        defaultIsOpen
      >
        <Combobox.SearchField label="Select Teammate" />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

## Behavior

The Combobox responds to user interaction with flexible selection methods and typeahead functionality.

### Single selecting

combobox-defaultselecteditem

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-defaultselecteditem?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Casey Maxwell" },
  { id: 2, name: "Giovanni Saunders" },
  { id: 3, name: "Harper Gonzalez" },
  { id: 4, name: "Jane Doe" },
  { id: 5, name: "Meadow Hunter" },
];
const defaultItem = items[0];

function App() {
  const [, setSelected] = useState<Item | null>();

  return (
    <Combobox
      items={items}
      itemToString={(item) => (item ? item.name : "")}
      onChange={setSelected}
      filterOptions={{ keys: ["name"] }}
      defaultSelectedItem={defaultItem}
      style={{ minWidth: "260px" }}
    >
      <Combobox.SearchField label="Select Teammate" />
      <Combobox.Content>
        {({ items }) => (
          <Combobox.List>
            {items.map((item, i) => (
              <Combobox.Item key={item.id} item={item} index={i}>
                {item.name}
              </Combobox.Item>
            ))}
          </Combobox.List>
        )}
      </Combobox.Content>
    </Combobox>
  );
}

export default App;
```

Clicking an option updates the text field value and closes the Combobox.

When reopening the Combobox with a selected value, the option matching that value is selected.

### Multi Selecting

combobox-defaultselecteditems

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-defaultselecteditems?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Casey Maxwell" },
  { id: 2, name: "Giovanni Saunders" },
  { id: 3, name: "Harper Gonzalez" },
  { id: 4, name: "Jane Doe" },
  { id: 5, name: "Meadow Hunter" },
];
const defaultItems = [items[1], items[4]];

function App() {
  const [, setSelected] = useState<Item[] | null>();

  return (
    <Combobox
      items={items}
      itemToString={(item) => (item ? item.name : "")}
      onChange={setSelected}
      filterOptions={{ keys: ["name"] }}
      multiple
      defaultSelectedItems={defaultItems}
    >
      <Combobox.SearchField label="Select Teammate" />
      <Combobox.Content>
        {({ items }) => (
          <Combobox.List>
            {items.map((item, i) => (
              <Combobox.Item key={item.id} item={item} index={i}>
                {item.name}
              </Combobox.Item>
            ))}
          </Combobox.List>
        )}
      </Combobox.Content>
    </Combobox>
  );
}

export default App;
```

#### Continuous selection

Continuous selection refers to a multiselect that stays open while users keep making selections.

Refer to the [usage guide](#continuous-multiselect) for when to use this variant.

combobox-disablecloseonselectitem

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-disablecloseonselectitem?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
];

function App() {
  const [, setSelected] = useState<Item[] | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "300px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        multiple
        disableCloseOnSelectItem
        defaultIsOpen
      >
        <Combobox.SearchField
          label="Select items"
          description="This is a Combobox.SearchField"
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

#### Select All

Multi-select Comboboxes support selecting all options at once.

combobox-selectall

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-selectall?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Apple" },
  { id: 2, name: "Banana" },
  { id: 3, name: "Blueberry" },
  { id: 4, name: "Grapefruit" },
  { id: 5, name: "Orange" },
  { id: 6, name: "Peach" },
  { id: 7, name: "Pomegranate" },
  { id: 8, name: "Raspberry" },
  { id: 9, name: "Strawberry" },
  { id: 10, name: "Watermelon" },
];

function App() {
  const [selectedItems, setSelected] = useState<Item[] | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "300px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        selectAll={{
          label: "Select All",
          onSelection: () => {
            setSelected(items);
          },
          isChecked: selectedItems?.length === items.length,
        }}
        selectedItems={selectedItems ?? undefined}
        multiple
        defaultIsOpen
      >
        <Combobox.SearchField label="Select Fruit" />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

### As Select-only

Configure the Combobox for scenarios requiring an HTML select-like experience.

comboboxselect

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/comboboxselect?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox, ComboboxSelect } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

function App() {
  const [selectedItem, setSelectedItem] = useState<Item | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <ComboboxSelect
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        selectedItem={selectedItem}
        onChange={setSelectedItem}
        defaultIsOpen
      >
        <Combobox.SelectTrigger
          label="Select an item"
          description="This is a Combobox.SelectTrigger"
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </ComboboxSelect>
    </div>
  );
}

export default App;
```

### Typeahead

Combobox supports typeahead, narrowing options in the popup as users type.

combobox-filteroptions

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-filteroptions?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Apple" },
  { id: 2, name: "Banana" },
  { id: 3, name: "Grapefruit" },
  { id: 4, name: "Orange" },
  { id: 5, name: "Pomegranate" },
];

function App() {
  const [, setSelected] = useState<Item | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        defaultIsOpen
      >
        <Combobox.SearchField label="Select Fruit" />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

### Rows

Comboboxes grow as the number of selections increases. Configure the maximum number of rows.

combobox-searchfield-maxrows-false

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-searchfield-maxrows-false?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox, Flex } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Casey Maxwell" },
  { id: 2, name: "Giovanni Saunders" },
  { id: 3, name: "Harper Gonzalez" },
  { id: 4, name: "Jane Doe" },
  { id: 5, name: "Meadow Hunter" },
];
const defaultItems = [items[1], items[4]];

function App() {
  const [, setSelected] = useState<Item[] | null>();

  return (
    <Flex gap={6} direction="column" style={{ maxWidth: "500px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        multiple
        defaultSelectedItems={defaultItems}
      >
        <Combobox.SearchField label="Select Teammate" />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>

      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        multiple
        defaultSelectedItems={[items[1], items[2], items[3], items[4]]}
      >
        <Combobox.SearchField label="Select Teammate" />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </Flex>
  );
}

export default App;
```

#### Truncated Chip

When there are more Chips than rows allowed in the Combobox, a truncated Chip will appear.

combobox-searchfield-maxrows-true

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-searchfield-maxrows-true?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox, Flex } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Apple" },
  { id: 2, name: "Banana" },
  { id: 3, name: "Blueberry" },
  { id: 4, name: "Grapefruit" },
  { id: 5, name: "Orange" },
  { id: 6, name: "Peach" },
  { id: 7, name: "Pomegranate" },
  { id: 8, name: "Raspberry" },
  { id: 9, name: "Strawberry" },
  { id: 10, name: "Watermelon" },
];
const defaultItems = [
  items[0],
  items[1],
  items[2],
  items[3],
  items[4],
  items[5],
  items[6],
  items[7],
  items[8],
  items[9],
];

function App() {
  const [, setSelected] = useState<Item[] | null>();

  return (
    <Flex gap={6} direction="column" style={{ maxWidth: "500px" }}>
      <Combobox
        items={items}
        itemToString={(item) => item?.name ?? ""}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        multiple
        defaultSelectedItems={defaultItems}
      >
        <Combobox.SearchField label="Select Fruit" maxRows={2} />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </Flex>
  );
}

export default App;
```

## Usage Guidelines

Use the Combobox when users need to select from many options.

| Standard | Requirement |
| - | - |
| Don'tNavigational contexts | In navigational contexts. |

### Selection methods

The main selection method for Combobox supports searching for a particular entity to make the selection. This pattern appears in applications like Slack when adding a new member to a channel.

| Scenario | Use a... |
| - | - |
| Has 10+ options | Regular Combobox |
| Users are not familiar with the options | Regular Combobox |
| Has 10 or fewer options | Select-only Combobox |
| Common user behavior is to search/filter for metadata instead of the entity's label | Continuous multiselect Combobox |
| Need for filtering, trees, secondary actions, action confirmation | Select Trigger + Complex Dialog |

#### Select-only

Use a Combobox as select-only in these scenarios:

* **Simple, static list**: Short lists of options (e.g., countries, states, or categories) that users easily recognize and navigate without much effort.
* **No need for search or filtering functionality**: Lists short enough that users can easily scan through all available choices.
* **Simple UX:** Select-only experiences require less complex interactions.

comboboxselect

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/comboboxselect?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox, ComboboxSelect } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

function App() {
  const [selectedItem, setSelectedItem] = useState<Item | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <ComboboxSelect
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        selectedItem={selectedItem}
        onChange={setSelectedItem}
        defaultIsOpen
      >
        <Combobox.SelectTrigger
          label="Select an item"
          description="This is a Combobox.SelectTrigger"
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </ComboboxSelect>
    </div>
  );
}

export default App;
```

#### Continuous multiselect

Combobox supports continuous multi-selection instead of closing after each selection. Use this pattern when users typically search for metadata to find multiple items.

* An example would be using "designer" as a search term to filter down to all designers and selecting multiple designers from that list.

combobox-disablecloseonselectitem

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-disablecloseonselectitem?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
];

function App() {
  const [, setSelected] = useState<Item[] | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "300px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        multiple
        disableCloseOnSelectItem
        defaultIsOpen
      >
        <Combobox.SearchField
          label="Select items"
          description="This is a Combobox.SearchField"
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

#### Select All

The Select All feature enables users to quickly select or deselect all available options within a multi-select Combobox. This pattern improves efficiency when working with large sets of items or when selecting most of the list is common.

combobox-selectall

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-selectall?file=src/App.tsx)

```tsx lines theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Apple" },
  { id: 2, name: "Banana" },
  { id: 3, name: "Blueberry" },
  { id: 4, name: "Grapefruit" },
  { id: 5, name: "Orange" },
  { id: 6, name: "Peach" },
  { id: 7, name: "Pomegranate" },
  { id: 8, name: "Raspberry" },
  { id: 9, name: "Strawberry" },
  { id: 10, name: "Watermelon" },
];

function App() {
  const [selectedItems, setSelected] = useState<Item[] | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "300px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        selectAll={{
          label: "Select All",
          onSelection: () => {
            setSelected(items);
          },
          isChecked: selectedItems?.length === items.length,
        }}
        selectedItems={selectedItems ?? undefined}
        multiple
        defaultIsOpen
      >
        <Combobox.SearchField label="Select Fruit" />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

#### Complex selection alternatives

When the Combobox is insufficient for a use case, use an alternative UI. These primarily combine the [Select Trigger](https://anvil.servicetitan.com/docs/components/select-trigger) with the [Dialog](https://anvil.servicetitan.com/docs/components/dialog/web.md), [Text Field](https://anvil.servicetitan.com/docs/components/text-field/web.md), [Listbox](https://anvil.servicetitan.com/docs/components/listbox/web.md), and [List View](https://anvil.servicetitan.com/docs/components/list-view/web.md) components, and may include others depending on need.

Rather than adding additional features to the Combobox, use the [Select Trigger](https://anvil.servicetitan.com/docs/components/select-trigger) for scenarios such as:

* Manual applying actions
* Needing secondary actions
* Tabbed division of options
* Multiple footer actions

### Alternatives

When there are only a few items to choose from, a [radio](https://anvil.servicetitan.com/docs/components/radio/web.md) or [checkbox](https://anvil.servicetitan.com/docs/components/checkbox/web.md) group may be more appropriate. When a particularly complex selection interaction is needed, a [Listbox](https://anvil.servicetitan.com/docs/components/listbox/web.md) in a special layout may be preferred.

#### Combobox vs Checkbox

Checkbox groups and the Combobox both allow multi-selection of a set of items. Checkbox groups should be used when there are only a few options. For larger options, Checkbox groups can still be used when there is space available and discovery of options is important. Comboboxes are good for 8 or more options and also when conserving space.

#### Combobox vs Menu

The Menu is used to perform actions on the page, and sometimes also a navigational context. The Combobox is used for choosing an option amongst a list, usually in the context of a Form.

#### Combobox vs Popover

When users need to select from many options, use the Combobox instead of the Popover. Avoid recreating a combobox-like or select-like interaction with a Popover.

#### Combobox vs Radio

Radio buttons and the Combobox both allow users to select a single option among a set. Use Radio buttons when there are between 2-7 options. Use a Combobox when there are 8 or more options available.

Additionally, in a group of Radio buttons all options are equally represented whereas a Combobox highlights a single option more prominently.

#### Combobox vs Search Field

Use the Combobox when selecting from options defined in an overlayed list, typically in the context of a form field. Use Search Field in situations requiring a traditional search experience, for filtering lists of items on the page, in tables, with large datasets, and for results requiring additional filtering.

#### Combobox vs Select Field

[Select Field](https://anvil.servicetitan.com/docs/components/select-field/web) is the eventual replacement for the Combobox component. Use Select Field when looking for features such as Dialog viewing, standardized content display, secondary actions, sectioning, or lazy loading.

Consider using the Combobox if needing a stable component in your application.

### How to Use

#### Labels and help

For information around concepts like labels, placeholder, and help, refer to the [Form pattern](https://anvil.servicetitan.com/docs/patterns/forms/web.md).

#### Sorting options

The Combobox does not prescribe how choices are sorted. Common sorting types include alphabetical, time-based, and categorical. Use a sort that matches user expectations.

![Combobox how
sort](https://mintlify.s3.us-west-1.amazonaws.com/servicetitan/images/docs/web/components/combobox/web/combobox-how-sort.png)

Examples of combobox sorts other than alphabetical:

## Content

Content within the Combobox should clearly communicate available options and selection states.

For content guidance, refer to the content guidance provided in the [Form pattern](https://anvil.servicetitan.com/docs/patterns/forms/web.md).

## Keyboard Interaction

Users can navigate the Combobox using standard keyboard controls.

### Text field

| Key | Interaction |
| - | - |
| Down Arrow | If the text field is not empty and the listbox is displayed, moves visual focus to the first suggested value. If the text field is empty and the listbox is not displayed, opens the listbox and moves visual focus to the first option. In both cases DOM focus remains on the text field. |
| Alt(Option) + Down Arrow | Opens the listbox without moving focus or changing selection. |
| Up Arrow | If the text field is not empty and the listbox is displayed, moves visual focus to the last suggested value. If the text field is empty, first opens the listbox if it is not already displayed and then moves visual focus to the last option. In both cases DOM focus remains on the text field. |
| Enter | Closes the listbox if it is displayed. |
| Escape | If the listbox is displayed, closes the listbox. If the listbox is not displayed, clears the text field. |

### Popup

NOTE: Even when the visual focus is on the listbox, DOM focus remains on the text field.

| Key | Interaction |
| - | - |
| Enter | Sets the text field value to the content of the focused option. Closes the popup. Sets visual focus on the text field. |
| Escape | Closes the popup. Sets visual focus on the text field. |
| Down Arrow | Moves visual focus to the next option. If visual focus is on the last option, moves visual focus to the first option. Note: This wrapping behavior is useful when Home and End move the editing cursor as described below. |
| Up Arrow | Moves visual focus to the previous option. If visual focus is on the first option, moves visual focus to the last option. Note: This wrapping behavior is useful when Home and End move the editing cursor as described below. |
| Right Arrow | Moves visual focus to the text field and moves the editing cursor one character to the right. |
| Left Arrow | Moves visual focus to the text field and moves the editing cursor one character to the left. |
| Home | Moves visual focus to the text field and places the editing cursor at the beginning of the field. |
| End | Moves visual focus to the text field and places the editing cursor at the end of the field. |

### Accessibility

Anvil provides most of the accessibility needs for Combobox out of the box, and only needs some additional considerations for library users.

For more guidance on building accessible form controls, see [custom component best practices](https://anvil.servicetitan.com/docs/resources/contributing/accessible-custom-components.md).

## Code

> [!WARNING]
>
> Combobox is deprecated. Use [SelectField](https://anvil.servicetitan.com/docs/components/select-field/code) for single selection or [MultiSelectField](https://anvil.servicetitan.com/docs/components/multi-select-field/code) for multiple selection. Combobox will be removed in Anvil2 5.0.

**Implementation**

combobox-playground

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-playground?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

function App() {
  const [selectedItems, setSelectedItems] = useState<Item[] | null>([]);

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Combobox
        multiple
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        selectedItems={selectedItems ?? []}
        onChange={setSelectedItems}
        filterOptions={{ keys: ["name"] }}
        defaultIsOpen
      >
        <Combobox.SearchField
          label="Label"
          placeholder="Placeholder"
          description="Description"
          moreInfo="More info!"
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

## Common Examples

```tsx theme={null}
import { useState } from "react";
import { Combobox } from "@servicetitan/anvil2";

const items = [
  { id: 1, name: "First item" },
  // ...more items...
];

const ExampleComponent = () => {
  const [selectedItem, setSelectedItem] = useState();

  return (
    <Combobox
      items={items}
      itemToString={(item) => item ? item.name : ""}
      itemToKey={(item) => item ? item.id : null}
      selectedItem={selectedItem}
      onChange={setSelectedItem}
      filterOptions={{ keys: ["name"] }}
    >
      <Combobox.SearchField label="Label" />
      <Combobox.Content>
        {({ items }) => (
          <Combobox.List>
            {items.map((item, i) => (
              <Combobox.Item
                key={item.id}
                item={item}
                index={i}
              >
                {item.name}
              </Combobox.Item>
            ))}
          </Combobox.List>
        )}
      </Combobox.Content>
    </Combobox>
  );
```

### Combobox components

The Anvil2 combobox is made up of a `Combobox` component and a few sub-components that can be used together to build simple or complex select drop-downs.

* `Combobox`: the parent component to configure comboboxes.
* `Combobox.SearchField`: used to create a searchable select input to use with a combobox list in a drop-down.
* `Combobox.Content`: popover that passes an `items` array to its `children` to construct combobox items.
* `Combobox.List`: organizes combobox items in the drop-down list.
* `Combobox.Item`: used to construct the items within the combobox drop-down.
* `Combobox.Empty`: optionally used to customize empty results message.

### Multi-selects

To allow the user to select multiple items, set the `multiple` prop of the `Combobox` to `true`. In addition, props such as `selectedItem` will be replaced with `selectedItems` (note the "s" at the end) and will expect an array.

combobox-playground

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-playground?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

function App() {
  const [selectedItems, setSelectedItems] = useState<Item[] | null>([]);

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Combobox
        multiple
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        selectedItems={selectedItems ?? []}
        onChange={setSelectedItems}
        filterOptions={{ keys: ["name"] }}
        defaultIsOpen
      >
        <Combobox.SearchField
          label="Label"
          placeholder="Placeholder"
          description="Description"
          moreInfo="More info!"
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

### Select all for multi-selects

To add a "Select All" option at the top of a multi-select combobox dropdown, use the `selectAll` prop. This prop accepts an object with `label`, `onSelection`, and `isChecked` properties. The `onSelection` callback is called when the user clicks the Select All option, and `isChecked` controls whether the checkbox appears checked.

Note: The "Select All" option does not automatically select all items when the combobox is opened. It is up to the developer to handle the selection of all items when the "Select All" option is clicked. This means it is incompatible with using `Combobox` in an uncontrolled way.

combobox-selectall

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-selectall?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Apple" },
  { id: 2, name: "Banana" },
  { id: 3, name: "Blueberry" },
  { id: 4, name: "Grapefruit" },
  { id: 5, name: "Orange" },
  { id: 6, name: "Peach" },
  { id: 7, name: "Pomegranate" },
  { id: 8, name: "Raspberry" },
  { id: 9, name: "Strawberry" },
  { id: 10, name: "Watermelon" },
];

function App() {
  const [selectedItems, setSelected] = useState<Item[] | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "300px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        selectAll={{
          label: "Select All",
          onSelection: () => {
            setSelected(items);
          },
          isChecked: selectedItems?.length === items.length,
        }}
        selectedItems={selectedItems ?? undefined}
        multiple
        defaultIsOpen
      >
        <Combobox.SearchField label="Select Fruit" />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

```tsx theme={null}
import { useState } from "react";
import { Combobox } from "@servicetitan/anvil2";

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
];

const ExampleComponent = () => {
  const [selectedItems, setSelectedItems] = useState([]);

  return (
    <Combobox
      multiple
      items={items}
      itemToString={(item) => item?.name ?? ""}
      itemToKey={(item) => item?.id ?? null}
      selectedItems={selectedItems}
      onChange={setSelectedItems}
      filterOptions={{ keys: ["name"] }}
      selectAll={{
        // Customize the label of the "Select All" option
        label: "Select All",
        // Callback function to handle the selection of all items
        onSelection: () => {
          // This is up to the developer to implement based on their use case
          setSelectedItems((prev) =>
            prev.length === items.length ? [] : items
          );
        },
        // Control whether the "Select All" option appears checked
        isChecked: selectedItems.length === items.length,
      }}
    >
      <Combobox.SearchField label="Label" />
      <Combobox.Content>
        {({ items }) => (
          <Combobox.List>
            {items.map((item, i) => (
              <Combobox.Item key={item.id} item={item} index={i}>
                {item.name}
              </Combobox.Item>
            ))}
          </Combobox.List>
        )}
      </Combobox.Content>
    </Combobox>
  );
};
```

### Building selects

The Anvil2 `Combobox` component is versatile due to its flexibility and robust set of sub-components. It can be used in place of the `Select` component from the original Anvil library to create a searchable select component.

combobox-multiple-false

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-multiple-false?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Casey Maxwell" },
  { id: 2, name: "Giovanni Saunders" },
  { id: 3, name: "Harper Gonzalez" },
  { id: 4, name: "Jane Doe" },
  { id: 5, name: "Meadow Hunter" },
];

function App() {
  const [, setSelected] = useState<Item | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        onChange={setSelected}
        filterOptions={{ keys: ["name"] }}
        defaultIsOpen
      >
        <Combobox.SearchField label="Select Teammate" />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

#### Notes for building selects

* The `itemToString` prop passes an `item` object and expects a `string` return type. This is used to format the text of each combobox item within the search field input (after selecting an item) based on the provided `item` object type.
* The `itemToKey` prop passes an `item` object and expects something that can be used to identify the item, such as an `id`. This is used for identity comparisons, so if this prop is omitted, the `item`s will be compared by reference equality instead.
* The `filterOptions` prop is used to filter the items using the [match-sorter](https://github.com/kentcdodds/match-sorter?tab=readme-ov-file) library. See [their docs](https://github.com/kentcdodds/match-sorter?tab=readme-ov-file#advanced-options) for more info on the options that can be provided.
* The `selectedItem`/`selectedItems` props allow the `Combobox` to be used as a controlled component.
* For easily managing the selected item state, the `onChange` prop accepts a `setState` function, which is the second item in the array that a `useState` function returns:

```tsx theme={null}
const ExampleComponent = () => {
  const [selected, setSelected] = useState();
  return <Combobox {...} onChange={setSelected} />
}
```

#### Compare using `itemToKey` or reference equality

The `itemToKey` prop is used to compare `items` using a unique identifier. By default, the `Combobox` component does searches and comparisons using reference equality. That means that the `Combobox` may not behave how you expect if your code is generating new references for your `items` on every render:

```tsx theme={null}
const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
];

const ExampleComponent = () => {
  const [selected, setSelected] = useState();

  // WARNING! This will create a new reference for every item on every render!
  const newItems = items.map(item => { ...item, someChange: Math.random() });

  return (
    <Combobox
      items={newItems}
    >
      {...}
    </Combobox>
  )
}
```

Some ways have stable references might be to perform the reference modifications outside of React's render cycle or to use `React.useMemo` to memoize computations on `items` and only update the references when something has meaningfully changed.

However, in cases like this, it's probably more likely you'd prefer to have your `items` compared by a specific key in your object rather than by reference equality. And so you can do that by passing in an `itemToKey` function that takes an item and returns a unique key:

```tsx theme={null}
const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
];

const ExampleComponent = () => {
  const [selected, setSelected] = useState();

  const newItems = items.map(item => { ...item, someChange: Math.random() });

  return (
    <Combobox
      items={newItems}
      itemToKey={(item) => item?.id}
    >
      {...}
    </Combobox>
  )
}
```

#### Passing filtered items through the combobox components

The `items` array passed to the `Combobox` is automatically filtered based on the user typing in the search input and the `keys` in the `filterOption` prop. After filtering, it is passed through the `Combobox.Content` as a parameter used to generate the `children`.

```tsx theme={null}
// objects in items array can have any type
const items = [
  { id: 1, label: "First item", alias: "one" },
  { id: 2, label: "Second item", alias: "two" },
  { id: 3, label: "Third item", alias: "three" },
];

const ExampleComponent = () => {
  const [selectedItems, setSelectedItems] = useState([]);

  return (
    <Combobox
      multiple
      items={items}
      itemToString={(item) => item?.label ?? ""}
      itemToKey={(item) => item?.id ?? null}
      selectedItems={selectedItems}
      onChange={setSelectedItems}
      /* strings in keys array should match the 
         searchable fields in items objects */
      filterOptions={{ keys: ["label", "alias"] }}
    >
      <Combobox.SearchField {...searchFieldProps} />
      <Combobox.Content>
        {/* matches items array, with filtering */}
        {({ items }) => (
          <Combobox.List>
            {items.map((item, index) => (
              <Combobox.Item key={item.id} item={item} index={index}>
                {item.label}
              </Combobox.Item>
            ))}
          </Combobox.List>
        )}
      </Combobox.Content>
    </Combobox>
  );
};
```

### Adding a new item when there is no exact match

To allow the user to add a new item when their search returns no exact matches, use the `Combobox.ItemAddNew` component. This component provides an `onSelection` callback, and that callback will need to be used to update both your list of items and your selected item.

Your `onSelection` callback will need to both update the list of items and update the `selectedItem`/`selectedItems`, so we recommend that you use a controlled `Combobox` when you need the ability to add a new item:

combobox-itemaddnew

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-itemaddnew?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox, Text } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

function App() {
  const [items, setItems] = useState<Item[]>([
    { id: 1, name: "First item" },
    { id: 2, name: "Second item" },
    { id: 3, name: "Third item" },
    { id: 4, name: "Fourth item" },
    { id: 5, name: "Fifth item" },
    { id: 6, name: "Sixth item" },
    { id: 7, name: "Seventh item" },
    { id: 8, name: "Eighth item" },
    { id: 9, name: "Ninth item" },
    { id: 10, name: "Tenth item" },
  ]);

  const [selectedItems, setSelectedItems] = useState<Item[] | null>([]);

  const handleAddNew = (inputValue: string) => {
    const newItem = { id: items.length + 1, name: inputValue };
    setItems((prevItems) => [...prevItems, newItem]);
    setSelectedItems((prevItems) =>
      prevItems != null ? [...prevItems, newItem] : [newItem],
    );
  };

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Combobox
        multiple
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        selectedItems={selectedItems ?? []}
        onChange={setSelectedItems}
        defaultIsOpen
        defaultInputValue="New item"
      >
        <Combobox.SearchField
          label="Select an item"
          description="Add a new item"
        />
        <Combobox.Content>
          {({ items, inputValue }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}

              <Combobox.Empty>
                <div
                  style={{
                    padding: "0.5rem 1rem",
                    textTransform: "uppercase",
                  }}
                >
                  <Text subdued size="small">
                    No match found
                  </Text>
                </div>
              </Combobox.Empty>

              <Combobox.ItemAddNew onSelection={handleAddNew}>
                + &nbsp; Add &ldquo;{inputValue}&rdquo;
              </Combobox.ItemAddNew>
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

### Select-only comboboxes

By default, comboboxes include a text input for searching and filtering items. To create a select-only combobox that acts similarly to an HTML select, use `ComboboxSelect` and `Combobox.SelectTrigger` instead of `Combobox` and `Combobox.SearchField`. `Combobox.Select` remains available as a deprecated alias for `ComboboxSelect`.

comboboxselect

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/comboboxselect?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox, ComboboxSelect } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

function App() {
  const [selectedItem, setSelectedItem] = useState<Item | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <ComboboxSelect
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        selectedItem={selectedItem}
        onChange={setSelectedItem}
        defaultIsOpen
      >
        <Combobox.SelectTrigger
          label="Select an item"
          description="This is a Combobox.SelectTrigger"
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </ComboboxSelect>
    </div>
  );
}

export default App;
```

#### Disable clearing selection on select-only combobox

To remove the "x" button that clears a selection in a select-only combobox, use the `disableClearSelection` prop.

**Note**: this does not work when `multiple` is `true`, due to the nature of clearing options in multi-select comboboxes.

comboboxselect-disableclearselection

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/comboboxselect-disableclearselection?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox, ComboboxSelect } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

function App() {
  const [selectedItem, setSelectedItem] = useState<Item | null>(items[1]);

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <ComboboxSelect
        disableClearSelection
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        selectedItem={selectedItem}
        onChange={setSelectedItem}
        defaultIsOpen
      >
        <Combobox.SelectTrigger
          label="Select an item"
          description="This is a Combobox.SelectTrigger"
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </ComboboxSelect>
    </div>
  );
}

export default App;
```

### Sorting combobox options

By default, Comboboxes sort options based on the order that they are provided via the `items` prop.

combobox-sort

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-sort?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

const reversedItems = items.reverse();

function App() {
  const [selectedItems, setSelectedItems] = useState<Item[] | null>([]);

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Combobox
        multiple
        items={reversedItems}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        selectedItems={selectedItems ?? []}
        onChange={setSelectedItems}
        filterOptions={{ keys: ["name"] }}
        defaultIsOpen
      >
        <Combobox.SearchField
          label="Select an item"
          description="This is a Combobox.SearchField"
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

### Controlled combobox

Comboboxes can be used uncontrolled by default, or can be used in a fully-controlled way by setting the `selectedItem` prop (or by using the `selectedItems` prop when used with `multiple` select):

combobox-controlled

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-controlled?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox, Flex, Button } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

function App() {
  const [selectedItem, setSelectedItem] = useState<Item | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Flex gap={8}>
        <Flex grow={1} direction="column" alignItems="center" gap={4}>
          <Button onClick={() => setSelectedItem(items[0])}>
            Set First Item
          </Button>
          <Button onClick={() => setSelectedItem(items[1])}>
            Set Second Item
          </Button>
          <Button onClick={() => setSelectedItem(items[2])}>
            Set Third Item
          </Button>
          <Button onClick={() => setSelectedItem(items[3])}>
            Set Fourth Item
          </Button>
          <Button onClick={() => setSelectedItem(items[4])}>
            Set Fifth Item
          </Button>
        </Flex>

        <Combobox
          items={items}
          itemToString={(item) => (item ? item.name : "")}
          itemToKey={(item) => (item ? item.id : null)}
          selectedItem={selectedItem}
          onChange={setSelectedItem}
          filterOptions={{ keys: ["name"] }}
          style={{ width: "50vw", maxWidth: "50%" }}
          defaultIsOpen
        >
          <Combobox.SearchField
            label="Select an item (single)"
            description="This is a Combobox.SearchField"
          />
          <Combobox.Content>
            {({ items }) => (
              <Combobox.List>
                {items.map((item, i) => (
                  <Combobox.Item key={item.id} item={item} index={i}>
                    {item.name}
                  </Combobox.Item>
                ))}
              </Combobox.List>
            )}
          </Combobox.Content>
        </Combobox>
      </Flex>
    </div>
  );
}

export default App;
```

combobox-controlled-multiple

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-controlled-multiple?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox, Flex, Button } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

function App() {
  const [selectedItems, setSelectedItems] = useState<Item[] | null>([]);

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Flex gap={8}>
        <Flex grow={1} direction="column" alignItems="center" gap={4}>
          <Button onClick={() => setSelectedItems([items[0]])}>
            Set First Item
          </Button>
          <Button onClick={() => setSelectedItems([items[1], items[2]])}>
            Set Second and Third Items
          </Button>
          <Button
            onClick={() => setSelectedItems([items[7], items[8], items[9]])}
          >
            Set Last Three Items
          </Button>
          <Button onClick={() => setSelectedItems([])}>Set Empty Array</Button>
        </Flex>

        <Combobox
          multiple
          items={items}
          itemToString={(item) => (item ? item.name : "")}
          itemToKey={(item) => (item ? item.id : null)}
          selectedItems={selectedItems ?? []}
          onChange={setSelectedItems}
          filterOptions={{ keys: ["name"] }}
          style={{ width: "50vw", maxWidth: "50%" }}
          defaultIsOpen
        >
          <Combobox.SearchField
            label="Select an item (multiple)"
            description="This is a Combobox.SearchField"
          />
          <Combobox.Content>
            {({ items }) => (
              <Combobox.List>
                {items.map((item, i) => (
                  <Combobox.Item key={item.id} item={item} index={i}>
                    {item.name}
                  </Combobox.Item>
                ))}
              </Combobox.List>
            )}
          </Combobox.Content>
        </Combobox>
      </Flex>
    </div>
  );
}

export default App;
```

### Default combobox selection

When using a Combobox in an uncontrolled way, Comboboxes can set an item as a default by using the `defaultSelectedItem` prop (or by using the `defaultSelectedItems` prop when used with `multiple` select):

combobox-defaultselecteditem

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-defaultselecteditem?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Casey Maxwell" },
  { id: 2, name: "Giovanni Saunders" },
  { id: 3, name: "Harper Gonzalez" },
  { id: 4, name: "Jane Doe" },
  { id: 5, name: "Meadow Hunter" },
];
const defaultItem = items[0];

function App() {
  const [, setSelected] = useState<Item | null>();

  return (
    <Combobox
      items={items}
      itemToString={(item) => (item ? item.name : "")}
      onChange={setSelected}
      filterOptions={{ keys: ["name"] }}
      defaultSelectedItem={defaultItem}
      style={{ minWidth: "260px" }}
    >
      <Combobox.SearchField label="Select Teammate" />
      <Combobox.Content>
        {({ items }) => (
          <Combobox.List>
            {items.map((item, i) => (
              <Combobox.Item key={item.id} item={item} index={i}>
                {item.name}
              </Combobox.Item>
            ))}
          </Combobox.List>
        )}
      </Combobox.Content>
    </Combobox>
  );
}

export default App;
```

combobox-defaultselecteditems

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-defaultselecteditems?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items: Item[] = [
  { id: 1, name: "Casey Maxwell" },
  { id: 2, name: "Giovanni Saunders" },
  { id: 3, name: "Harper Gonzalez" },
  { id: 4, name: "Jane Doe" },
  { id: 5, name: "Meadow Hunter" },
];
const defaultItems = [items[1], items[4]];

function App() {
  const [, setSelected] = useState<Item[] | null>();

  return (
    <Combobox
      items={items}
      itemToString={(item) => (item ? item.name : "")}
      onChange={setSelected}
      filterOptions={{ keys: ["name"] }}
      multiple
      defaultSelectedItems={defaultItems}
    >
      <Combobox.SearchField label="Select Teammate" />
      <Combobox.Content>
        {({ items }) => (
          <Combobox.List>
            {items.map((item, i) => (
              <Combobox.Item key={item.id} item={item} index={i}>
                {item.name}
              </Combobox.Item>
            ))}
          </Combobox.List>
        )}
      </Combobox.Content>
    </Combobox>
  );
}

export default App;
```

### Selected item customization

`Combobox`es with `multiple` select can customize the selected state of an item using the `selectedItemProps` prop on the `Combobox.SearchField`. This prop accepts a function that will pass the selected item as an parameter to allow for things like customizing the display color:

combobox-selecteditemprops

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-selecteditemprops?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
  color: string;
};

const items = [
  { id: 1, name: "Red", color: "red" },
  { id: 2, name: "Purple", color: "purple" },
  { id: 3, name: "Black", color: "black" },
  { id: 4, name: "Gray", color: "gray" },
  { id: 5, name: "Gold", color: "gold" },
  { id: 6, name: "Cyan", color: "cyan" },
  { id: 7, name: "Pink", color: "pink" },
  { id: 8, name: "Blue", color: "blue" },
  { id: 9, name: "Green", color: "green" },
];

function App() {
  const [, setSelectedItems] = useState<Item[] | null>([
    items[4],
    items[5],
    items[6],
  ]);

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Combobox
        multiple
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        defaultSelectedItems={[items[4], items[5], items[6]]}
        onChange={setSelectedItems}
        filterOptions={{ keys: ["name"] }}
        defaultIsOpen
      >
        <Combobox.SearchField
          label="Select a color"
          description="This is an example of color customization"
          selectedItemProps={(item) => ({
            color: item.color,
          })}
        />
        <Combobox.Content>
          {({ items }) => (
            <Combobox.List>
              {items.map((item, i) => (
                <Combobox.Item key={item.id} item={item} index={i}>
                  {item.name}
                </Combobox.Item>
              ))}
            </Combobox.List>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

### Disabling combobox popovers

Comboboxes can be used to create searchable select lists without a drop-down. If `disablePopover` is set to `true` on the `Combobox.Content`, the list will always render. This is especially useful if the combobox exists within a custom [popover](https://anvil.servicetitan.com/docs/components/popover/design).

combobox-disablepopover

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-disablepopover?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox, Popover } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: string;
  name: string;
};

const technicians = [
  { id: "cs-0", name: "Cory Sparks" },
  { id: "jb-1", name: "Jessica Brees" },
  { id: "jc-2", name: "Johnny Carpenter" },
  { id: "rp-3", name: "Rusty Pipes" },
  { id: "sp-4", name: "Silvia Plomería" },
];

function App() {
  const [selectedItems, setSelectedItems] = useState<Item[] | null>([]);

  return (
    <div style={{ minHeight: "284px", paddingInlineEnd: "18rem" }}>
      <Popover placement="right-start" defaultOpen>
        <Popover.Button>Add technician(s)</Popover.Button>
        <Popover.Content>
          <Combobox
            multiple
            items={technicians}
            itemToString={(item) => (item ? item.name : "")}
            itemToKey={(item) => (item ? item.id : null)}
            selectedItems={selectedItems ?? []}
            onChange={setSelectedItems}
            filterOptions={{ keys: ["name"] }}
            style={{ width: "15rem" }}
          >
            <Combobox.SearchField label="Label" />
            <Combobox.Content disablePopover>
              {({ items }) => (
                <Combobox.List>
                  {items.map((item, i) => (
                    <Combobox.Item key={item.id} item={item} index={i}>
                      {item.name}
                    </Combobox.Item>
                  ))}
                </Combobox.List>
              )}
            </Combobox.Content>
          </Combobox>
        </Popover.Content>
      </Popover>
    </div>
  );
}

export default App;
```

### Custom combobox empty state

By default, if no items exist in the filtered combobox results, a simple "No results found" message is displayed. To customize this, use the `Combobox.Empty` component.

combobox-empty

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/combobox-empty?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Combobox, Flex, Text } from "@servicetitan/anvil2";
import { useState } from "react";

type Item = {
  id: number;
  name: string;
};

const items = [
  { id: 1, name: "First item" },
  { id: 2, name: "Second item" },
  { id: 3, name: "Third item" },
  { id: 4, name: "Fourth item" },
  { id: 5, name: "Fifth item" },
  { id: 6, name: "Sixth item" },
  { id: 7, name: "Seventh item" },
  { id: 8, name: "Eighth item" },
  { id: 9, name: "Ninth item" },
  { id: 10, name: "Tenth item" },
];

function App() {
  const [selectedItem, setSelectedItem] = useState<Item | null>();

  return (
    <div style={{ minWidth: "384px", minHeight: "284px" }}>
      <Combobox
        items={items}
        itemToString={(item) => (item ? item.name : "")}
        itemToKey={(item) => (item ? item.id : null)}
        selectedItem={selectedItem}
        onChange={setSelectedItem}
        filterOptions={{ keys: ["name"] }}
        defaultIsOpen
        defaultInputValue="XYZ"
      >
        <Combobox.SearchField label="Select an item" />
        <Combobox.Content>
          {({ items }) => (
            <>
              <Combobox.Empty>
                <Flex
                  gap="1"
                  alignItems="center"
                  justifyContent="center"
                  direction="column"
                  style={{ padding: "var(--size-2)" }}
                >
                  <Text variant="headline" el="h3" size="medium">
                    😕 No matches
                  </Text>
                  <Text>Please try again.</Text>
                </Flex>
              </Combobox.Empty>
              <Combobox.List>
                {items.map((item, i) => (
                  <Combobox.Item key={item.id} item={item} index={i}>
                    {item.name}
                  </Combobox.Item>
                ))}
              </Combobox.List>
            </>
          )}
        </Combobox.Content>
      </Combobox>
    </div>
  );
}

export default App;
```

### Combobox virtualization example

`Combobox.Content` renders a function that passes down the list of filtered items as children, allowing the `Combobox.List` component to be used with virtualization libraries, which often require an additional wrapper component around the items being virtualized. The following example uses `react-window`'s `FixedSizeList` component for virtualizing the list of items:

```tsx theme={null}
import { useState } from "react";
import { Combobox } from "@servicetitan/anvil2";
import { FixedSizeList as List } from "react-window";

const items = [
  { id: 1, name: "First item" },
  // ...more items...
];

const ExampleComponent = () => {
  const [selectedItem, setSelectedItem] = useState();

  return (
    <Combobox
      items={items}
      itemToString={(item) => (item ? item.name : "")}
      itemToKey={(item) => (item ? item.id : null)}
      onChange={setSelectedItem}
      filterOptions={{ keys: ["name"] }}
    >
      <Combobox.SearchField label="Virtualization" />
      <Combobox.Content>
        {({ items }) => (
          <List
            height={Math.min(640, 34 * items.length)}
            width="100%"
            itemCount={items.length}
            itemSize={34}
            innerElementType={Combobox.List}
          >
            {({ index, style }) => (
              <Combobox.Item
                key={index}
                item={items[index]}
                index={index}
                style={style}
              >
                {items[index].name}
              </Combobox.Item>
            )}
          </List>
        )}
      </Combobox.Content>
    </Combobox>
  );
};
```

## Testing

Interactive sub-elements carry a stable `data-anv-part` attribute so end-to-end tests can target them directly. The library owns the part names; you supply the instance identifier.

Attach your own `data-*` attribute (such as `data-cy` or `data-testid`) to `Combobox` / `Combobox.Select`. It is forwarded to the root wrapper, letting you scope queries to a single instance:

```tsx theme={null}
<Combobox data-cy="fruit-picker" items={items} itemToString={…}>
  <Combobox.SearchField label="Fruit" />
  …
</Combobox>
```

```ts theme={null}
// Target the input within this specific combobox
cy.get('[data-cy="fruit-picker"] [data-anv-part="input"]').type("Ban");
```

| `data-anv-part` | Element |
| - | - |
| `input` | Search field input (`Combobox.SearchField`) |
| `trigger` | Select trigger surface (`Combobox.SelectTrigger`) |
| `clear-button` | Button that clears the selection |
| `toggle-button` | Button that opens and closes the menu (search mode) |
| `chip` | Removable chip for a selected value (multi-select) |
| `menu` | Option list container |
| `option` | An individual option row |
| `popover` | Menu container in popover display mode |

Options also carry `data-id` from `itemToKey(item)` so you can pick one among many: `[data-anv-part="option"][data-id="1"]`.

> [!NOTE]
>
> The menu renders in the browser's top layer (`menu`, `option`, and `popover` parts), outside the Combobox wrapper. Descendant queries scoped to your wrapper attribute will not match these parts. Target them by their part attribute directly. Only one menu is open at a time.

**Combobox and ComboboxSelect Props**

```tsx theme={null}
<Combobox
  items={items}
  itemToString={(item) => item?.name ?? ""}
  itemToKey={(item) => item?.id ?? null}
  multiple={false}
  onChange={setSelectedItem}
  filterOptions={{ keys: ["name"] }}
/>
```

## `Combobox` and `ComboboxSelect` Props

In addition to the props listed below, the `Combobox` and `ComboboxSelect` components can accept any valid HTML `div` props.

* The default `Combobox` also accepts the props listed in the [downshift UseComboboxProps type](https://github.com/downshift-js/downshift/blob/v8.5.0/typings/index.d.ts#L537).

* The `ComboboxSelect` component (also available as the deprecated `Combobox.Select` alias) extends the [downshift UseSelectProps type](https://github.com/downshift-js/downshift/blob/v8.5.0/typings/index.d.ts#L340). Note: Props related to the input are not included for ComboboxSelect, since there is no search field. (`defaultInputValue, inputId`, etc.)

**defaultSelectedItem** `Item`

The default selected item for single-select combobox.

**defaultSelectedItems** `Item[]`

The default selected item(s) for multi-select combobox.

**disabled** `boolean` (default: false)

Disables the combobox, preventing user interaction.

**disableClearInputValueOnSelectItem** `boolean`

Prevent input from clearing when item is selected. **Note:** Only works with
`Combobox` with `multiple={true}`

**disableClearSelection** `boolean` (default: false)

Remove the clear button to disable user clearing the input after selecting.
**Note:** Only works with `ComboboxSelect` when `multiple` is not `true`

**disableCloseOnClickOutside** `boolean` (default: false)

Prevent the drop-down popover from closing when the user clicks outside of it.

**disableCloseOnSelectItem** `boolean`

Prevent the drop-down from closing when item is selected. **Note:** Only works
with `Combobox` with `multiple={true}`

**filterOptions** `MatchSorterOptions`

See the [match-sorter MatchSorterOptions
type](https://github.com/kentcdodds/match-sorter/blob/v6.3.4/src/index.ts#L50)
**Note:** Not available on `ComboboxSelect`

**groupBy** `string`

Name of the property on each item to group by. When provided, items are organized into labeled sections in the dropdown based on the value of this property.

**groupSorter** `(a: ComboboxGroupByValue, b: ComboboxGroupByValue) =\> number` (default: (a, b) => String(a).localeCompare(String(b)))

Function to compare two group values for sorting. Must return a negative number if `a` should appear before `b`, and a positive number if `b` should appear before `a`. `ComboboxGroupByValue` is `string | number`.

**groupToString** `(groupByValue: ComboboxGroupByValue) =\> string | null`

Function to convert group values to display labels. When not provided, the raw group key value is used as the label. `ComboboxGroupByValue` is `string | number`.

**multiple** `boolean` (default: false)

**onChange** `(item: Item | null) =\> void | (items: Item[]) =\> void`

Callback when selection changes. For single-select, receives the selected item or null. For multi-select, receives an array of selected items.

**open** `boolean` (default: false)

**readOnly** `boolean` (default: false)

Makes the combobox read-only, allowing focus but preventing changes.

**selectAll** `\{ label?: string; onSelection: () =\> void; isChecked: boolean \}`

Configuration for "Select All" option in multi-select comboboxes. When provided, adds a "Select All"
option at the top of the dropdown list. Only available when `multiple={true}`.

**Combobox.SearchField and Combobox.SelectTrigger Props**

```tsx theme={null}
<Combobox.SearchField
  id="combobox-1"
  label="Select an item"
  required={true}
  moreInfo="Additional information"
  prefix={{ icon: SearchIcon }}
/>
```

## `Combobox.SearchField` and `Combobox.SelectTrigger` Props

**id** `string`

**moreInfo** `string`

**moreInfoOpen** `boolean` (default: false)

Control opening the `moreInfo` tooltip.

**prefix** `string | \{ icon: IconProps \}`

Prefix content displayed before the input.

**required** `boolean` (default: false)

**selectedItemProps** `(Item) =\> ChipProps`

This function passes the selected item as a parameter and returns an object to
merge into the selected item `Chip` props.

**Combobox.Content Props**

```tsx theme={null}
<Combobox.Content disablePopover={false}>
  {({ items }) => (
    <Combobox.List>
      {items.map((item, index) => (
        <Combobox.Item key={item.id} item={item} index={index}>
          {item.name}
        </Combobox.Item>
      ))}
    </Combobox.List>
  )}
</Combobox.Content>
```

## `Combobox.Content` Props

**children** `(\{ items, inputValue \}) =\> ReactNode`

**disablePopover** `boolean` (default: false)

**Combobox.List Props**

```tsx theme={null}
<Combobox.List>
  {items.map((item, index) => (
    <Combobox.Item key={item.id} item={item} index={index}>
      {item.name}
    </Combobox.Item>
  ))}
</Combobox.List>
```

## `Combobox.List` Props

**children** `ReactNode`

**Combobox.Item Props**

```tsx theme={null}
<Combobox.Item index={0} item={items[0]} disabled={false}>
  Item content
</Combobox.Item>
```

## `Combobox.Item` Props

**index** `number` *required*

**item** `Item` *required*

**children** `ReactNode`

**disabled** `boolean`

**Combobox.ItemAddNew Props**

```tsx theme={null}
<Combobox.ItemAddNew onSelection={(inputValue) => console.log(inputValue)}>
  Add new item
</Combobox.ItemAddNew>
```

## `Combobox.ItemAddNew` Props

**children** `ReactNode`

**onSelection** `(inputValue) =\> void`

**Combobox.Empty Props**

```tsx theme={null}
<Combobox.Empty>No results found</Combobox.Empty>
```

## `Combobox.Empty` Props

**children** `ReactNode`


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.