Combobox
A searchable choice whose value is a selected item, separate from the search query.
On this page
Select a known audience.
Code
import { Combobox } from "@bosunkit/components/combobox";
import { Field } from "@bosunkit/components/field";
import type { ReactElement } from "react";
const items: readonly string[] = ["Engineering", "Product", "Investors"];
export const description: string =
"Search the known audiences; typing filters the list and choosing commits one of its values.";
export default function Showcase(): ReactElement {
return (
<Field.Root>
<Field.Label>Audience</Field.Label>
<Combobox.Root items={items} defaultValue="Engineering">
<Combobox.Input />
<Combobox.Portal>
<Combobox.Positioner sideOffset={4}>
<Combobox.Popup>
<Combobox.Empty>No matching audience</Combobox.Empty>
<Combobox.List>
{(item: string): ReactElement => (
<Combobox.Item key={item} value={item}>
{item}
</Combobox.Item>
)}
</Combobox.List>
</Combobox.Popup>
</Combobox.Positioner>
</Combobox.Portal>
</Combobox.Root>
<Field.Description>Select a known audience.</Field.Description>
</Field.Root>
);
}
Composition
Import { Combobox } from @bosunkit/components/combobox. Named parts follow
Base UI Combobox.
Each part retains the upstream render, ref, DOM props, state attributes and event contracts.
The kit supplies its typography, surfaces and scoped overlay presentation.
Examples
Custom composition
Select a known audience.
Code
import { Combobox } from "@bosunkit/components/combobox";
import { Field } from "@bosunkit/components/field";
import type { ReactElement } from "react";
const items: readonly string[] = ["Engineering", "Product", "Investors"];
export const description: string =
"Search the known audiences; typing filters the list and choosing commits one of its values.";
export default function Showcase(): ReactElement {
return (
<Field.Root>
<Field.Label>Audience</Field.Label>
<Combobox.Root items={items} defaultValue="Engineering">
<Combobox.Input />
<Combobox.Portal>
<Combobox.Positioner sideOffset={4}>
<Combobox.Popup>
<Combobox.Empty>No matching audience</Combobox.Empty>
<Combobox.List>
{(item: string): ReactElement => (
<Combobox.Item key={item} value={item}>
{item}
</Combobox.Item>
)}
</Combobox.List>
</Combobox.Popup>
</Combobox.Positioner>
</Combobox.Portal>
</Combobox.Root>
<Field.Description>Select a known audience.</Field.Description>
</Field.Root>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| disabled | boolean | undefined | – | Whether the component should ignore user interaction. |
| className | string | ((state: State) => string | undefined) | undefined | – | CSS class applied to the element, or a function that returns a class based on the component's state. |
| render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | undefined | – | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.
Accepts a ReactElement or a function that returns the element to render. |
| style | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) | undefined | – | Style applied to the element, or a function that returns a style object based on the component's state. |
Also takes every attribute of Primitive.Input.Props.
| Prop | Type | Default | Description |
|---|---|---|---|
| initialFocus | boolean | React.RefObject<HTMLElement | null> | ((openType: InteractionType) => void | boolean | HTMLElement | null) | undefined | – | Determines the element to focus when the popup is opened.
- false: Do not move focus.
- true: Move focus based on the default behavior (first tabbable element or popup).
- RefObject: Move focus to the ref element.
- function: Called with the interaction type (mouse, touch, pen, or keyboard).
Return an element to focus, true to use the default behavior, or false/undefined to do nothing. |
| finalFocus | boolean | React.RefObject<HTMLElement | null> | ((closeType: InteractionType) => void | boolean | HTMLElement | null) | undefined | – | Determines the element to focus when the popup is closed.
- false: Do not move focus.
- true: Move focus based on the default behavior (trigger or previously focused element).
- RefObject: Move focus to the ref element.
- function: Called with the interaction type (mouse, touch, pen, or keyboard).
Return an element to focus, true to use the default behavior, or false/undefined to do nothing. |
| className | string | ((state: State) => string | undefined) | undefined | – | CSS class applied to the element, or a function that returns a class based on the component's state. |
| render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | undefined | – | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.
Accepts a ReactElement or a function that returns the element to render. |
| style | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) | undefined | – | Style applied to the element, or a function that returns a style object based on the component's state. |
Also takes every attribute of Primitive.Popup.Props.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | – | |
| onClick | BaseUIComponentProps<'div', ComboboxItemState>['onClick'] | undefined | – | An optional click handler for the item when selected.
It fires when clicking the item with the pointer, as well as when pressing Enter with the keyboard if the item is highlighted when the Input or List element has focus. |
| index | number | undefined | – | The index of the item in the list. Improves performance when specified by avoiding the need to calculate the index automatically from the DOM. |
| value | any | – | A unique value that identifies this item. |
| disabled | boolean | undefined | – | Whether the component should ignore user interaction. |
| className | string | ((state: State) => string | undefined) | undefined | – | CSS class applied to the element, or a function that returns a class based on the component's state. |
| render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | undefined | – | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.
Accepts a ReactElement or a function that returns the element to render. |
| style | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) | undefined | – | Style applied to the element, or a function that returns a style object based on the component's state. |
| nativeButton | boolean | undefined | – | Whether the component renders a native <button> element when replacing it
via the render prop.
Set to true if the rendered element is a native button. |
Also takes every attribute of Primitive.Item.Props.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | ((item: any, index: number) => React.ReactNode) | – | |
| className | string | ((state: State) => string | undefined) | undefined | – | CSS class applied to the element, or a function that returns a class based on the component's state. |
| render | React.ReactElement | ComponentRenderFn<RenderFunctionProps, State> | undefined | – | Allows you to replace the component's HTML element
with a different tag, or compose it with another component.
Accepts a ReactElement or a function that returns the element to render. |
| style | React.CSSProperties | ((state: State) => React.CSSProperties | undefined) | undefined | – | Style applied to the element, or a function that returns a style object based on the component's state. |
Also takes every attribute of Primitive.List.Props.
Asynchronous suggestions
Code
import { AsyncCombobox, type Suggestion } from "@bosunkit/components/combobox";
import { FormField } from "@bosunkit/components/form-field";
import type { ReactElement } from "react";
export const description: string =
"The selected record has both an ID and display text; the input's accessible label comes from Field.";
const items: readonly Suggestion[] = [
{ value: "eng", label: "Engineering" },
{ value: "prod", label: "Product" },
];
export default function AsyncExample(): ReactElement {
return (
<FormField label="Audience">
<AsyncCombobox
name="audience"
defaultValue={items[0]}
suggest={(query: string): Promise<readonly Suggestion[]> =>
Promise.resolve(
items.filter((item: Suggestion): boolean => item.label.toLowerCase().includes(query.toLowerCase())),
)
}
/>
</FormField>
);
}
AsyncCombobox accepts suggest(query, signal) and minQueryLength. The caller owns the lookup; superseded requests are aborted and late answers are ignored. The callback keeps Base UI's cancellable event details.
| Prop | Type | Default | Description |
|---|---|---|---|
| suggestrequired | (query: string, signal: AbortSignal) => Promise<readonly Suggestion[]> | – | Caller-owned asynchronous lookup; no transport belongs to the kit. |
| minQueryLength | number | undefined | – | Minimum trimmed query length. |
| value | Suggestion | null | undefined | – | Selected record, including display text; null means no selection. Typed queries are separate. |
| defaultValue | Suggestion | null | undefined | – | Initial selected record when uncontrolled. |
| onValueChange | Base.Root.Props<Suggestion>["onValueChange"] | – | Original cancellable selection event; only an item or null can be selected. |
| inputValue | string | undefined | – | Query text, independent of the selected value. |
| onInputValueChange | Base.Root.Props<Suggestion>["onInputValueChange"] | – | Reports query changes. |
| onBlur | Base.Input.Props["onBlur"] | – | Input blur handler, preserving the native focus event. |
| id | string | undefined | – | Control ID for an external label. |
| aria-label | string | undefined | – | Accessible control name when no visible label is associated. |
| aria-describedby | string | undefined | – | Hint and error element IDs. |
| placeholder | string | undefined | – | Input placeholder. |
| readOnly | boolean | undefined | – | Prevent editing. |
| disabled | boolean | undefined | – | Prevent interaction and submission. |
| required | boolean | undefined | – | Require a selection in a native form. |
| name | string | undefined | – | Submitted field name. |
| motion | boolean | undefined | true | Enable popup entrance motion. |
| className | string | undefined | – | Input classes. |
| ref | Ref<HTMLInputElement> | undefined | – | Input element. |
Select a known audience.
Related
- Component API: naming, state, composition and compatibility.
- Interaction states: focus, disabled and selected presentation.
- Form field: the assembled label and validation recipe.