Options can be provided either synchronously (static or already loaded) or asynchronously (based on a search).
Example: Pre-defined options
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
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
The label of the combobox field.
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
An optional placeholder text for your input.
Whether or not the field should be disabled.
ComboboxOption
An object containing:
The value that will be saved into your form data when this option is selected.
The label the user will see for this option
An optional description the user will see for this option
An optional avatar to display for this option
An optional icon to display for this option, an AttioIcon
.
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:
- Avatar
- Color
- 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:
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
.
search
(query: string) => Promise<ComboboxOption[] | CategorizedComboboxOption[]>
An async function that, given a search query, fetches an array of “matching” ComboboxOption
s.What “matching” means is up to the developer.