This component is returned by useForm().
Options can be provided either synchronously (static or already loaded) or asynchronously (based on a search).

Example: Pre-defined options

pick-color-dialog.tsx
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

github-user-schema.ts
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.
get-github-user.server.ts
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
}
search-github-users.server.ts
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.
github-options-provider.ts
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 />.
pick-github-user-dialog.tsx
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

label
string
required
The label of the combobox field.
name
string
required
The path to the string value of the input field in your form schema.e.g. "status", "shipping.address.state"
options
Array<ComboboxOption> | ComboboxOptionsProvider
required
Either an array of ComboboxOptions, or a ComboboxOptionsProvider to load them.
placeholder
string
An optional placeholder text for your input.
disabled
boolean
Whether or not the field should be disabled.

ComboboxOption

An object containing:
value
string
required
The value that will be saved into your form data when this option is selected.
label
string
required
The label the user will see for this option
description
string
An optional description the user will see for this option
avatarUrl
string
An optional avatar to display for this option
icon
AttioIcon
An optional icon to display for this option, an AttioIcon.
color
string
An optional CSS color for the option. It will be displayed in a little circle next to the label.

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:
categoryLabel
string
A category label to display this option under

ComboboxOptionProvider

An object containing:
getOption
(value: string) => Promise<Omit<ComboboxOption, "value">>
An async function that, given an option value, fetches the rest of the ComboboxOption.
An async function that, given a search query, fetches an array of “matching” ComboboxOptions.What “matching” means is up to the developer.