kenos UIBeta
Primitive

Select

A headless select with combobox + listbox pattern. Interop-first defaults: modal={false}, portal={false}. Pointer open keeps focus on the trigger; keyboard open moves focus into the listbox. Supports single and multiple selection, items prop for label maps, and Select.HiddenSelect for native form submission.

Examples

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

Default

Inside a Dialog

Kenos defaults to portal={false} and modal={false} so the listbox stays in the Dialog subtree. Escape closes the Select only (stopPropagation, scoped to content focus) — the parent dialog stays open. Pointer open keeps focus on the trigger; keyboard open moves focus into the listbox with aria-activedescendant.

Forms

Add name on Select.Root and render Select.HiddenSelect for native HTML submit and constraint validation.

Form Integration

Bind value and onValueChange to your form library. All examples validate with Zod.

Multiple selection

Pass multiple on Select.Root to enable multi-select. Items toggle on click and the listbox stays open. Value shape becomes string[].

Portal & container

Use portal={true} on Select.Content when clipping is an issue. Inside a Dialog, pass a container ref to keep the listbox in the Dialog subtree while escaping overflow: hidden.

Dialog.Content (portal container)

API Reference

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

Root props

value / defaultValue / onValueChangestring | null | string[]

Controlled/uncontrolled selected value. string[] when multiple={true}.

open / defaultOpen / onOpenChangeboolean

Listbox open state.

namestring

Forwarded to Select.HiddenSelect for form submit.

disabled / required / readOnlyboolean

Root constraints.

modalbooleandefault: false

Opt-in focus trap + aria-modal on Content. Renders Select.Backdrop.

multiplebooleandefault: false

Multi-select mode. Toggle items on click; listbox stays open.

itemsRecord<string, string>

Value → label map. Resolves Select.Value labels without rendering every Item.

isItemEqualToValue(a: string, b: string) => boolean

Custom string comparator for selection matching (default: ===). Not for object values.

openOnFocusbooleandefault: false

Open the listbox when the trigger receives focus. Does not reopen after Escape/select restore focus.

Content props

portalbooleandefault: false

Portal to document.body — avoid inside Dialogs.

alignItemWithTriggerbooleandefault: false

Offset content to cover the trigger (by trigger height). Does not scroll the selected item into alignment. On Safari pinch-zoom, automatically falls back to standard anchoring.

containerHTMLElement | RefObject<HTMLElement>

Custom portal target (e.g. Dialog.Content ref). Requires portal={true}.

side / align / sameWidth

Floating UI positioning via @kenos-ui/utils.

lazyMountbooleandefault: true

Skip DOM until first open.

onOpenChangeComplete(open: boolean) => void

Fires when open transitions finish, including presence exit.

Parts (Tier 2–4)

Select.ClearTriggerspan[role=button]

Clears the current value without opening the listbox. Place as a sibling of Trigger (not nested inside the button).

Select.ScrollUpButton / ScrollDownButtonbutton

Scroll the list when options overflow. Auto-hidden when not needed.

scrollToIndex(index)context method

Programmatically scroll the list to an item index.

Data attributes

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

Keyboard

KeyAction
Arrow ↓ / Enter / Space (closed)Open the listbox and move focus into the list.
Arrow ↑ / ↓Move highlight; skips disabled items.
Home / EndFirst / last enabled option.
Type charactersTypeahead match on textValue.
Enter / SpaceSelect highlighted option.
EscapeClose listbox (when focus is in content or on trigger); stopPropagation for Dialog interop.