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

# <Combobox />

> A combobox input which allows searching for and selecting from a list of options.

<img className="dark:hidden" width="720" height="440" noZoom src="https://mintcdn.com/attio/6iYi7YnGZIZchWq2/images/combobox.png?fit=max&auto=format&n=6iYi7YnGZIZchWq2&q=85&s=9b4ffce51404b703d9cb529bf649daca" data-path="images/combobox.png" />

<img className="hidden dark:block" width="720" height="440" noZoom src="https://mintcdn.com/attio/6iYi7YnGZIZchWq2/images/combobox-dark.png?fit=max&auto=format&n=6iYi7YnGZIZchWq2&q=85&s=83f390563b448bd1ea3587b030dc6667" data-path="images/combobox-dark.png" />

<Note>This component is returned by [`useForm()`](../../forms/use-form).</Note>

Options can be provided either synchronously (static or already loaded) or asynchronously (based on a search).

## Example: Pre-defined options

```tsx pick-color-dialog.tsx theme={"system"}
import React from "react"
import {Forms, useForm, showToast, ComboboxOption, TextBlock} from "attio/client"

const colorOptions = [
  {label: "Red", value: "#ff0000"},
  {label: "Green", value: "#00ff00"},
  {label: "Blue", value: "#0000ff"},
] satisfies ComboboxOption[]

export function PickColorDialog() {
  const {Form, SubmitButton, Combobox} = useForm(
    {
      color: Forms.string(),
    },
    {
      color: "",
    },
  )
  return (
    <Form
      onSubmit={async (values) => {
        await showToast({
          title: "Form submitted",
          variant: "success",
          text: `You picked ${values.color}`,
        })
      }}
    >
      <TextBlock>Pick a color</TextBlock>
      <Combobox label="Color" name="color" options={colorOptions} />
      <SubmitButton label="Submit" />
    </Form>
  )
}
```

## Example: Asynchronously loaded options

```ts github-user-schema.ts theme={"system"}
import {z} from "zod"

export const githubUserSchema = z.object({
  id: z.number(),
  login: z.string(),
})

export type GithubUser = z.infer<typeof githubUserSchema>
```

Because we cannot `fetch()` from the client, we need to define server functions
to talk to the third party API.

```ts get-github-user.server.ts theme={"system"}
import {GithubUser, githubUserSchema} from "./github-user-schema"

export default async function getGithubUser(id: string): Promise<GithubUser | undefined> {
  const user = await fetch(`https://api.github.com/users/${id}`)
  const userData = await user.json()
  const parsed = githubUserSchema.safeParse(userData)
  if (!parsed.success) {
    return undefined
  }
  return parsed.data
}
```

```ts search-github-users.server.ts theme={"system"}
import {GithubUser, githubUserSchema} from "./github-user-schema"

export default async function searchGithubUsers(search: string): Promise<GithubUser[]> {
  const users = await fetch(`https://api.github.com/search/users?q=${search}`)
  const usersData = await users.json()
  const parsed = githubUserSchema.array().safeParse(usersData.items)
  if (!parsed.success) {
    return []
  }
  return parsed.data
}
```

Now we can create our async combobox options provider.

```ts github-options-provider.ts theme={"system"}
import {ComboboxOptionsProvider} from "attio/client"
import getGithubUser from "./get-github-user.server"
import searchGithubUsers from "./search-github-users.server"

export const githubUserOptionsProvider = {
  getOption: async (value: string) => {
    const user = await getGithubUser(value)
    return user ? {label: user.login} : undefined
  },

  search: async (search: string) => {
    const users = await searchGithubUsers(search)
    return users.map((user) => ({
      value: user.id.toString(),
      label: user.login,
    }))
  },
} satisfies ComboboxOptionsProvider
```

And then we give that options provider to the `<Combobox />`.

```tsx pick-github-user-dialog.tsx theme={"system"}
import React from "react"
import {Forms, useForm, showToast, TextBlock} from "attio/client"
import {githubUserOptionsProvider} from "./github-users-options-provider"

export function PickGithubUserDialog() {
  const {Form, SubmitButton, Combobox} = useForm(
    {
      assignTo: Forms.string(),
    },
    {
      assignTo: "",
    },
  )
  return (
    <Form
      onSubmit={async (values) => {
        await showToast({
          title: "Form submitted",
          variant: "success",
          text: `You picked user id #${values.assignTo}`,
        })
      }}
    >
      <TextBlock>Pick a Github user:</TextBlock>
      <Combobox label="Assign to" name="assignTo" options={githubUserOptionsProvider} />
      <SubmitButton label="Submit" />
    </Form>
  )
}
```

## Props

<ParamField path="label" type="string" required>
  The label of the combobox field.
</ParamField>

<ParamField path="name" type="string" required>
  The path to the `string` value of the input field in your [form schema](../../forms/form-schema).

  e.g. `"status"`, `"shipping.address.state"`
</ParamField>

<ParamField path="options" type="Array<ComboboxOption> | ComboboxOptionsProvider" required>
  Either an array of [ComboboxOption](#comboboxoption)s, or a
  [ComboboxOptionsProvider](#comboboxoptionsprovider) to load them.
</ParamField>

<ParamField path="decorated" type="boolean">
  If `decorated` is `true`, the combobox requires decorated options, meaning that each option must
  provide one of `avatarUrl`, `color`, or `icon`.
</ParamField>

<ParamField path="placeholder" type="string">
  An optional placeholder text for your input.
</ParamField>

<ParamField path="disabled" type="boolean">
  Whether or not the field should be disabled.
</ParamField>

# ComboboxOption

An object containing:

<ParamField path="value" type="string" required>
  The value that will be saved into your form data when this option is selected.
</ParamField>

<ParamField path="label" type="string" required>
  The label the user will see for this option
</ParamField>

<ParamField path="description" type="string">
  An optional description the user will see for this option
</ParamField>

<ParamField path="avatarUrl" type="string">
  An optional avatar to display for this option
</ParamField>

<ParamField path="icon" type="AttioIcon">
  An optional icon to display for this option, an [`AttioIcon`](../../icons).
</ParamField>

<ParamField path="color" type="string">
  An optional CSS color for the option. It will be displayed in a little circle next to the label.
</ParamField>

## Combobox Option Decorations

The priority of decorations goes:

1. Avatar
2. Color
3. Icon

e.g. If there is an avatar, it will be shown; else if there is a color, it will be shown, etc.

# CategorizedComboboxOption

An object that extends `ComboboxOption` and also includes:

<ParamField path="categoryLabel" type="string">
  A category label to display this option under
</ParamField>

# ComboboxOptionProvider

An object containing:

<ParamField path="getOption" type="(value: string) => Promise<Omit<ComboboxOption, 'value'>>">
  An async function that, given an option value, fetches the rest of the
  [`ComboboxOption`](#comboboxoption).
</ParamField>

<ParamField path="search" type="(query: string) => Promise<ComboboxOption[] | CategorizedComboboxOption[]>">
  An async function that, given a search query, fetches an array of “matching” [`ComboboxOption`](#comboboxoption)s.

  What “matching” means is up to the developer.
</ParamField>
