kenos UIBeta
Primitive

Combobox

A headless combobox with type-to-filter, Input-first focus (aria-activedescendant), and an Empty state when nothing matches. open and inputValue are independent — Trigger toggles the list without clearing the query. Interop-first defaults: modal={false}, portal={false}, Content anchored to the Input.

Examples

You can explore the combobox primitive in the following curated examples. Every demo below is fully interactive and keyboard-navigable.

Default

Type to filter

Typing in Combobox.Input filters options by textValue (defaults to the item label). Pass a custom filter on Combobox.Root to change the matching logic. Combobox.Empty renders when nothing matches.

Inside a Dialog

Combobox Content is inline by default with modal={false} and portal={false} so the listbox stays in the Dialog subtree. Focus stays on Combobox.Input (aria-activedescendant). Escape closes the Combobox only — the parent dialog stays open.

Forms

Add name on Combobox.Root and render Combobox.HiddenInput for native HTML submit.

API Reference

Props, data attributes, and keyboard interactions for Combobox. Import from @kenos-ui/react-combobox; parts use data-part and data-* attributes for styling.

Root props

value / defaultValue / onValueChangestring | null

Controlled/uncontrolled selected value.

inputValue / defaultInputValue / onInputValueChangestring

Controlled/uncontrolled filter text in the input.

open / defaultOpen / onOpenChangeboolean

Listbox open state.

namestring

Native form field name for Combobox.HiddenInput.

openOnFocusbooleandefault: false

Open when Input receives focus. Breaking vs 0.2.x (which always opened on focus).

openOnChangebooleandefault: true

Open when typing while closed. Independent of Trigger toggle.

disabled / required / readOnlyboolean

Root constraints.

modalbooleandefault: false

Opt-in focus trap + aria-modal on Content.

itemsRecord<string, string>

Value → label map. Resolves input display when items are not mounted.

isItemEqualToValue(item: string, value: string) => boolean

Custom comparator for value matching.

filter(item: { textValue: string }, query: string) => boolean

Custom filter for type-to-filter. Default: case-insensitive substring on textValue.

Content props

side / align / sameWidth

Floating UI positioning via @kenos-ui/utils. Reference is always the Input.

portalbooleandefault: false

Render Content in a portal. Default false for Dialog interop.

containerHTMLElement | RefObject | null

Portal mount target when portal is true. Defaults to document.body.

lazyMountbooleandefault: true

Skip DOM until first open.

onOpenChangeComplete(open: boolean) => void

Fires when open transitions finish, including presence exit.

Parts

Combobox.Emptydiv

Rendered when the filter matches no items. Place inside Content after List.

Combobox.Clearspan[role=button]

Clears value and input text without opening the listbox.

Combobox.ItemIndicatorspan

Selected check; reads ItemContext or an explicit value prop.

Combobox.HiddenInputinput[type=hidden]

Native hidden field when name is set on Root.

Data attributes

AttributeOn partDescription
[data-open]On input/trigger when listbox is open.
[data-selected]On selected option.
[data-highlighted]Keyboard/hover highlight.
[data-disabled]Disabled input, trigger, or option.

Keyboard

KeyAction
Type charactersFilter options by textValue (substring match).
Arrow ↑ / ↓Move highlight via aria-activedescendant; skips disabled items.
Home / EndFirst / last enabled option.
EnterSelect highlighted option; closes listbox.
EscapeClose listbox; stopPropagation for Dialog interop.