Combobox

Combobox presents user with a set of options and allows to select one of them.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",
},
];

return (
<Combobox
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

#

#

Combobox should be disabled, when user shouldn't be allowed to interact with it.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState("first");

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
];

return (
<Combobox
isDisabled
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

Individual options can be disabled too.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",
},
];

return (
<Combobox
isOptionDisabled={(option) => option.value === "second"}
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

You can also provide a custom message when an option is disabled:

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",
},
];

return (
<Combobox
isOptionDisabled={(option) => {
if (option.value === "third") {
return "This option is not available";
}
return option.value === "second";
}}
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

#

Mark combobox as loading, when options are fetched on the fly and are not yet available.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [];

return (
<Combobox
isLoading
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

#

Invalid combobox indicates that current value isn't what the system expects.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
];

return (
<Combobox
isInvalid
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

#

Clearable combobox should be used when empty selection is acceptable.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState("first");

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
];

return (
<Combobox
isClearable
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

#

Options can display an additional descriptive text underneath the label.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "First",
description: "This is the first option.",
value: "first",
},
{
label: "Second",
description: "This is the second option.",
value: "second",
},
{
label: "Third",
description: "This is the third option.",
value: "third",
},
];

return (
<Combobox
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

#

Options can display additional accessories view before and after the label. You can show an image using an image accessory. This is useful for showing logos when selecting sources or destinations, for example.

Additionally, using the showPlaceholderIcon prop will render a dotted circle in the placeholder state.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "PostgreSQL",
value: "postgresql",
logo: "https://cdn.svgporn.com/logos/postgresql.svg",
},
{
label: "MySQL",
value: "mysql",
logo: "https://cdn.svgporn.com/logos/mysql-icon.svg",
},
{
label: "Planetscale",
value: "planetscale",
logo: "https://cdn.svgporn.com/logos/planetscale.svg",
},
];

return (
<Combobox
showPlaceholderIcon
optionAccessories={(option) => ({
leftAccessory: {
type: "image",
url: option.logo,
},
})}
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}

Icons can be accessories too.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "Dollar",
value: "dollar",
icon: CurrencyDollarIcon,
color: "success.base",
},
{
label: "Euro",
value: "euro",
icon: CurrencyEuroIcon,
},
{
label: "Pound",
value: "pound",
icon: CurrencyPoundIcon,
},
];

return (
<Combobox
optionAccessories={(option) => ({
leftAccessory: {
type: "icon",
icon: option.icon,
color: option.color,
},
})}
placeholder="Select an option..."
value={value}
options={options}

Accessories can be shown on the left or right.

import { Combobox, SparkleIcon } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "Dollar",
value: "dollar",
icon: CurrencyDollarIcon,
color: "success.base",
},
{
label: "Euro",
value: "euro",
icon: CurrencyEuroIcon,
},
{
label: "Pound",
value: "pound",
icon: CurrencyPoundIcon,
},
];

return (
<Combobox
showPlaceholderIcon
optionAccessories={(option) => ({
leftAccessory: {
type: "icon",
icon: option.icon,
color: option.color,
tooltip: option.tooltip,
},
rightAccessory: {
type: "icon",

The combobox supports filtering options based on the input value. This state is accessible via the onSearchUpdate prop. Any change that's typed in the input will call this function.

import { BadgeInput } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState("first");

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",
},
];

return (
<Combobox
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
onSearchUpdate={(value) => {
console.log("search value:", value);
}}
/>
);
}

#

Set renderInputInControl to false to render the combobox input inside of the popover.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "PostgreSQL",
value: "postgresql",
logo: "https://cdn.svgporn.com/logos/postgresql.svg",
},
{
label: "MySQL",
value: "mysql",
logo: "https://cdn.svgporn.com/logos/mysql-icon.svg",
},
{
label: "Planetscale",
value: "planetscale",
logo: "https://cdn.svgporn.com/logos/planetscale.svg",
},
];

return (
<Combobox
isClearable
showPlaceholderIcon
renderInputInControl={false}
optionAccessories={(option) => ({
leftAccessory: {
type: "image",
url: option.logo,
},
})}
placeholder="Select an option..."
value={value}

#

You can disable sorting and filtering internally by setting disableSortingAndFiltering to true. This could be helpful if the options are already sorted and filtered externally.

function Example() {
const [value, setValue] = React.useState(["first"]);

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",
},
];

return (
<Combobox
disableSortingAndFiltering
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

#

Combobox allows user to create a new option on the fly, when no suitable option exists. For that, enable supportsCreatableOptions and set an onCreateOption function that will handle creation of options. Options can be created asynchronously, but you need to handle loading state yourself via isLoading prop.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const [options, setOptions] = React.useState([
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",
},
]);

const createOption = React.useCallback((inputValue) => {
if (inputValue === "Forbidden") {
return;
}

const value = inputValue.toLowerCase();

const newOption = {
label: inputValue,
value,
};

setOptions((previousOptions) => [...previousOptions, newOption]);
setValue(value);
}, []);

#

You don't have to create objects with label and value keys as shown in the examples above. Combobox supports any objects, as long as you provide a label and value for each option via optionLabel and optionValue functions. description may be replaced with the optionDescription function.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
id: "first",
title: "First",
comment: "This is the first option",
},
{
id: "second",
title: "Second",
comment: "This is the second option",
},
{
id: "third",
title: "Third",
comment: "This is the third option",
},
];

return (
<Combobox
placeholder="Select an option..."
value={value}
options={options}
optionDescription={(option) => option.comment}
optionLabel={(option) => option.title}
optionValue={(option) => option.id}
onChange={setValue}
/>
);
}

#

There's a version of Combobox called GroupedCombobox, that supports groups of options.

import { GroupedCombobox, SparkleIcon } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const optionGroups = [
{
label: "Group A",
options: [
{
label: "First",
value: "first",
icon: CurrencyDollarIcon,
},
{
label: "Second",
value: "second",
icon: CurrencyEuroIcon,
},
{
label: "Third",
value: "third",
icon: CurrencyPoundIcon,
},
],
},
{
label: "Group B",
options: [
{
label: "Fourth",
value: "fourth",
},
{
label: "Fifth",
value: "fifth",

#

Use the heavy variant to emphasize the combobox when in views with many selects or in-line with text.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",
},
];

return (
<Combobox
placeholder="Select an option..."
value={value}
variant="heavy"
options={options}
onChange={setValue}
/>
);
}

#

Use the alternative variant to deemphasize the combobox when there are many selects.

import { Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",
},
];

return (
<Combobox
placeholder="Select an option..."
value={value}
variant="alternative"
options={options}
onChange={setValue}
/>
);
}

#

The size prop impacts font-size and height. Default is set to md.

To set the width, use the width prop instead.

This combobox is 24px tall
This combobox is 32px tall
This combobox is 40px tall
This grouped combobox is 24px tall
This grouped combobox is 32px tall
This grouped combobox is 40px tall
import { Column, Combobox } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();
const [groupedValue, setGroupedValue] = React.useState();

const options = [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",
},
];

const optionGroups = [
{
label: "Group A",
options: [
{
label: "First",
value: "first",
},
{
label: "Second",
value: "second",
},
{
label: "Third",
value: "third",

#

When rendering smaller-width comboboxes, you may end up with options that are quite tall. To make the options easier to read, pass in a specific width for the popover using popoverWidth.

It is recommended to match widths, when possible.

import { Select } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "First",
value: "first",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed lobortis elementum posuere. Sed quis nisi purus. Nullam volutpat augue eget augue ullamcorper, eget maximus ipsum placerat. Curabitur a est eu ante posuere facilisis vitae sit amet lorem. Suspendisse potenti. Donec orci magna, pharetra lobortis nulla eget, dapibus convallis lorem. Vestibulum at tincidunt lorem.",
},
{
label: "Second",
value: "second",
description:
"Proin ut ultricies est. Curabitur ornare, arcu egestas malesuada pellentesque, mauris velit pretium nisi, et sodales ex libero a libero. Donec purus neque, blandit vel ligula at, consequat iaculis libero. Aliquam et diam est. Quisque risus dui, condimentum rhoncus ex id, interdum hendrerit nunc. Nulla ultricies bibendum nunc, sed pellentesque eros porttitor eget. Cras hendrerit congue quam, vitae sodales metus pharetra at. Maecenas nec ultricies lacus, vel aliquam diam. Sed risus augue, porta nec nulla sit amet, lobortis maximus leo. Quisque in ante aliquam, convallis sapien porttitor, sollicitudin turpis. Vivamus euismod, sem a vulputate blandit, lorem diam imperdiet lacus, id ullamcorper diam dui at mi. Phasellus luctus ante elit, sit amet laoreet elit accumsan eget. Aenean ut eros quam. Integer mollis dolor dui.",
},
{
label: "Third",
value: "third",
description:
"Sed vel vulputate augue, quis vulputate eros. Interdum et malesuada fames ac ante ipsum primis in faucibus. Sed sagittis ornare feugiat. Nulla quam tellus, gravida ut malesuada sed, ultricies et erat. Duis velit neque, commodo ut suscipit ac, pellentesque sit amet massa. Proin gravida libero in enim fringilla, vitae lacinia arcu auctor. Quisque eleifend lectus ut metus viverra viverra.",
},
];

return (
<Combobox
popoverWidth="sm"
width="4xs"
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
/>
);
}

Show a header section within the combobox when the options are displayed.

import { Select } from "@hightouchio/ui";

function Example() {
const [value, setValue] = React.useState();

const options = [
{
label: "Africa",
value: "africa",
},
{
label: "EUNA",
value: "euna",
},
{
label: "Middle East",
value: "middle east",
},
{
label: "North America",
value: "north america",
disabled: true,
},
];

return (
<Combobox
headerLabel="Region"
headerDescription="Customers in this sales region"
placeholder="Select an option..."
value={value}
options={options}
onChange={setValue}
isOptionDisabled={(o) => o.disabled}
/>
);

#

#

  • When single selection is required.
  • When user should be able to create new options, if needed.
  • When selecting from user-generated data, where searching might come handy for long lists.

#

#

#

NameDefaultDescription
headerLabel

string

Show a header label at the top when displaying the options.

headerDescription

string

Show a header description at the top when displaying the options.

isDisabled

boolean

Determines if combobox is disabled.

isLoading

boolean

Indicates that options are being loaded.

isInvalid

boolean

Indicates that combobox is in invalid state.

isClearablefalseboolean

Determines if selection can be cleared.

isOptionDisabled

(option: Option) => boolean | string

Function to determine whether an option should be disabled. If a string is returned, it will be used as a disabled message.

emptyOptionsMessage"No options"string

Text to show inside a dropdown when there are no options.

supportsCreatableOptions

boolean

Determines if user is allowed to create a new option, if it's not present already.

createOptionMessage"Create "[input value]""(inputValue: string) => string

Text to show inside dropdown when creating a new option.

disableSortingAndFilteringfalseboolean

Determines if the options should be sorted and filtered internally.

comboboxRef

RefObject<HTMLInputElement>

Reference to the combobox input element.

options

Option[]

Available options. `Option` is a generic, so type of options will be inferred.

optionLabel

(option: Option) => string

Function to extract label from an option. If it's not provided, `label` field will be used as a label.

optionDescription

(option: Option) => string

Function to extract description from an option. If it's not provided, `description` field will be used as a label.

optionValue

(option: Option) => OptionValue

Function to extract value from an option. If it's not provided, `value` field will be used as a value.

optionAccessories

SelectOptionAccessoriesGetter<Option>

Function to show accessories near the option label.

placeholder

string

Text to show inside combobox when no option is selected.

removePortalfalseboolean

Determines if the select dropdown should be rendered in a portal.

renderInputInControltrueboolean

Determines if the input should be rendered in the control.

showPlaceholderIconfalseboolean

Determines if the placeholder icon should be shown. Only available when optionAccessory is defined.

value

OptionValue | undefined

Selected option.

variant"default""default" | "alternative" | "heavy"

Determines the appearance of the combobox.

size"md""sm" | "md" | "lg"

Combobox height.

width"xs""4xs" | "3xs" | "2xs" | "xs" | "sm" | "md" | "lg" | "100%"

Combobox width.

popoverWidthundefined"4xs" | "3xs" | "2xs" | "xs" | "sm" | "md" | "lg"

The dropdown width. If not provided, the select width will be used.

onChange

(value: OptionValue | undefined) => void

Callback for when user selects a different option or clears the selection.

onCreateOption

(inputValue: string) => Promise<void> | void

Callback for creating a new option. It can be async.

onClose

() => void

Callback for when user closes the select.

onOpen

() => void

Callback for when user opens the select.

onSearchUpdate

(inputValue: string) => void

Callback for when user changes the input value.

valueLabel

(option: Option) => string

Function to format a selected option's label. If not provided, `label` field will be used as a label.

#

NameDefaultDescription
isDisabled

boolean

Determines if combobox is disabled.

isLoading

boolean

Indicates that options are being loaded.

isInvalid

boolean

Indicates that combobox is in invalid state.

isClearablefalseboolean

Determines if selection can be cleared.

isOptionDisabled

(option: Option) => boolean | string

Function to determine whether an option should be disabled. If a string is returned, it will be used as a disabled message.

emptyOptionsMessage"No options"string

Text to show inside a dropdown when there are no options.

disableSortingAndFilteringfalseboolean

Determines if the options should be sorted and filtered internally.

optionGroups

Array<{ label: string; options: Option[]; }>

Available options. `Option` is a generic, so type of options will be inferred.

optionLabel

(option: Option) => string

Function to extract label from an option. If it's not provided, `label` field will be used as a label.

optionValue

(option: Option) => OptionValue

Function to extract value from an option. If it's not provided, `value` field will be used as a value.

optionDescription

(option: Option) => string

Function to extract description from an option. If it's not provided, `description` field will be used as a label.

optionAccessories

SelectOptionAccessoriesGetter<Option>

Function to show an accessory view near the option label.

placeholder

string

Text to show inside combobox when no option is selected.

removePortalfalseboolean

Determines if the select dropdown should be rendered in a portal.

renderInputInControltrueboolean

Determines if the input should be rendered in the control.

showPlaceholderIconfalseboolean

Determines if the placeholder icon should be shown. Only available when optionAccessories is defined.

size"md""sm" | "md" | "lg"

Combobox height.

value

OptionValue | undefined

Selected option.

variant"default""default" | "alternative" | "heavy"

Determines the appearance of the combobox.

width"xs""4xs" | "3xs" | "2xs" | "xs" | "sm" | "md" | "lg" | "100%"

Combobox width.

popoverWidthundefined"4xs" | "3xs" | "2xs" | "xs" | "sm" | "md" | "lg"

The dropdown width. If not provided, the select width will be used.

onChange

(value: OptionValue | undefined) => void

Callback for when user selects a different option or clears the selection.

onSearchUpdate

(inputValue: string) => void

Callback for when user changes the input value.

valueLabel

(option: Option) => string

Function to format a selected option's label. If not provided, `label` field will be used as a label.

comboboxRef

RefObject<HTMLInputElement>

Reference to the comboBox element.