Combobox
comboboxFilters selectable options through either a trigger popup or an inline input.
Usage
Search within elastic layer (Figure 4 paradigm)
The trigger button displays the selected options. Click to expand the floating layer with the search box.
<Combobox items={fruits}>
<ComboboxTrigger placeholder="Select Fruit" />
<ComboboxContent searchPlaceholder="Search for fruits...">
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxContent>
</Combobox>Inline auto-completion
The fields are visible in the input box itself and can be filtered by typing directly. clearable displays the clear button.
<Combobox items={fruits}>
<ComboboxInput placeholder="Search for fruits..." clearable />
<ComboboxContent>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxContent>
</Combobox>Default selected value
defaultValue Pass in the option object as an uncontrolled initial value.
<Combobox items={fruits} defaultValue={fruits[2]}>
<ComboboxTrigger placeholder="Select Fruit" />
<ComboboxContent searchPlaceholder="Search for fruits...">
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxContent>
</Combobox>Disabled and invalid state
disabled is overall gray; invalid trigger is marked red.
<>
<Combobox items={fruits} defaultValue={fruits[0]} disabled>
<ComboboxTrigger placeholder="Select Fruit" />
<ComboboxContent searchPlaceholder="Search for fruits...">
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxContent>
</Combobox>
<Combobox items={fruits}>
<ComboboxTrigger placeholder="Select Fruit" invalid />
<ComboboxContent searchPlaceholder="Search for fruits...">
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxContent>
</Combobox>
</>Dimensions
size controls the trigger height (sm / md / lg).
<Combobox items={fruits}>
<ComboboxTrigger size="sm" placeholder="Select Fruit" />
<ComboboxContent searchPlaceholder="Search for fruits...">
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxContent>
</Combobox>When to use
Use Combobox when users need to filter a substantial option set as they type. It supports a trigger that opens a searchable popup, an inline autocomplete field, and chip-based multiple selection. Use Select for a small fixed list, SecretField to display an existing secret, or Mentions for inline references such as @mentions.
Import
import { Combobox, ComboboxInput, ComboboxTrigger, ComboboxContent, ComboboxItem, ComboboxChips, ComboboxChip } from "@hulianui/ui"Props
Combobox extends Base UI Combobox.Root<ComboboxItemData, Multiple>; the table below lists HulianUI's common additions.
| Name | Type | Default | Description |
|---|---|---|---|
| items | ComboboxItemData[] | — | Options in { value, label } form. The label is displayed while the value identifies the option. |
| value | ComboboxItemData|ComboboxItemData[] | — | Controlled selection; use an array when multiple is true. |
| defaultValue | Same as above | — | Initial selection when uncontrolled. |
| multiple | boolean | false | Changes value and onValueChange to arrays. |
| virtualized | boolean | true once items reaches 100 | Virtualizes the list so only visible options are rendered. Decided from the option count when omitted — see Usage guidelines. |
| disabled | boolean | false | Disables the control. |
ComboboxTrigger displays the selected label or placeholder and opens the searchable popup.
| Name | Type | Default | Description |
|---|---|---|---|
| size | "sm"|"md"|"lg" | "md" | Trigger size. |
| placeholder | string | — | Text shown when nothing is selected. |
| invalid | boolean | false | Applies invalid styling when used outside Field. |
| className | string | — | Additional class name for the trigger. |
ComboboxInput provides inline autocomplete: the visible field is also the search input.
| Name | Type | Default | Description |
|---|---|---|---|
| size | "sm"|"md"|"lg" | "md" | Input size. |
| placeholder | string | — | Input placeholder. |
| invalid | boolean | false | Applies invalid styling. |
| clearable | boolean | false | Shows a clear button when the field has a value. |
| className | string | — | Additional class name for the input. |
ComboboxContent
| Name | Type | Default | Description |
|---|---|---|---|
| searchPlaceholder | string | — | Adds a search field to the popup when used with ComboboxTrigger. Omit it when ComboboxInput already provides inline search. |
| side | "top"|"bottom" | — | Preferred side of the trigger on which to place the popup. |
| align | "start"|"center"|"end" | — | Popup alignment relative to the trigger. |
| sideOffset | number | — | Distance from the trigger in pixels. |
| onListScroll | UIEventHandler<HTMLDivElement> | — | Called when the option list scrolls. e.currentTarget is the scroll container, which can be inspected to implement load-on-scroll pagination; see RemoteSelect. |
| footer | ReactNode | — | Fixed content below the scrolling list, such as loading, count, or end-of-results feedback. |
| className | string | — | Additional class name for the popup. |
ComboboxItem
| Name | Type | Default | Description |
|---|---|---|---|
| value * | ComboboxItemData | — | Complete { value, label } option object. |
| disabled | boolean | false | Disables this option. |
| className | string | — | Additional class name for the option. |
ComboboxChips is the multiple-selection field shell and accepts size, invalid, placeholder, className, and children.ComboboxChip renders one selected value and accepts className and children.
Events
Combobox inherits events from Base UI Combobox.Root.
| Event | Type | Description |
|---|---|---|
| onValueChange | (value) => void | Called when the selection changes; value is an array in multiple mode. |
Slots
Combobox
| Slot | Type | Description |
|---|---|---|
| children | ReactNode | Trigger or input plus popup content. |
ComboboxContent
| Slot | Type | Description |
|---|---|---|
| children * | (item, index) => ReactNode | Render function invoked once for each filtered option. |
| emptyMessage | ReactNode | Content shown when no option matches the query. |
ComboboxItem
| Slot | Type | Description |
|---|---|---|
| children * | ReactNode | Visible option content. |
ComboboxChips
| Slot | Type | Description |
|---|---|---|
| children | ReactNode | Selected chips and the inline input. |
ComboboxChip
| Slot | Type | Description |
|---|---|---|
| children * | ReactNode | Visible chip content. |
Usage guidelines
- Lists of 100 options or more are virtualized automatically — you do not pass
virtualizedyourself. Only the visible options stay in the DOM, and row height is estimated at a fixed 32px without per-item measurement. The defaultComboboxItemis exactly 32px tall, so most usage is unaffected. If your render function returns rows of a different height (two lines of text, an avatar, custom padding or font size throughclassName), scrollbar length and item placement drift apart as the list grows — nothing throws, and short lists never reproduce it; the jump only shows once you scroll past the first screens. Passvirtualized={false}for those rows, or make them 32px tall. - Virtualization also affects tests and scripts that assume every option is in the DOM:
getAllByRole("option")returns only the visible window, anddocument.querySelectorcannot find options you have not scrolled to. Assert totals againstdata-hulian-virtual-counton the list container, or passvirtualized={false}for that test. - Components built on Combobox inherit this: the
searchableskin of Select and the candidate list of RemoteSelect both virtualize once they hold 100 options. ComboboxItemreceives the entire{value,label}object asvalue, not just a string. Passvalue={item}from the render function so Base UI can derive both the label and value.- Set
searchPlaceholderonComboboxContentwhen usingComboboxTriggerto provide search inside the popup. WithComboboxInput, the inline input is already the search field. - Enabling
multiplechangesvalueandonValueChangeto arrays. Controlled state must use the corresponding array type. - Pass
invalidonly when Combobox is used outside Field. Field supplies invalid styling automatically for nested controls.
Related
SecretField · Listbox · Mentions · InputOTP · Rating · Upload
Playground
<Combobox items={items} defaultValue={items[0]}>
<ComboboxTrigger size="md" placeholder="Select fruit" />
<ComboboxContent searchPlaceholder="Search for fruits...">
{(item) => <ComboboxItem key={item.value} value={item}>{item.label}</ComboboxItem>}
</ComboboxContent>
</Combobox>