@affino/combobox-core
Stability: Stable
Headless combobox reducer that layers filtering + disclosure state on top of listbox primitives from @affino/listbox-core.
Overview
Use combobox-core when you need query/filter state plus listbox-style selection and keyboard focus management in one headless primitive.
Installation
bash
npm install @affino/combobox-coreQuick start
ts
import {
createComboboxState,
setComboboxOpen,
setComboboxFilter,
moveComboboxFocus,
activateComboboxIndex,
} from "@affino/combobox-core"
const context = {
mode: "single" as const,
loop: true,
disabled: false,
optionCount: filteredOptions.length,
isDisabled: (index: number) => filteredOptions[index]?.disabled ?? false,
}
let state = createComboboxState()
state = setComboboxOpen(state, true)
state = setComboboxFilter(state, "ap")
state = moveComboboxFocus({ state, context, delta: 1 })
state = activateComboboxIndex({ state, context, index: state.listbox.activeIndex })Core API
createComboboxState(initial?)setComboboxOpen(state, open)setComboboxFilter(state, filter)moveComboboxFocus({ state, context, delta, extend? })activateComboboxIndex({ state, context, index, toggle?, extend? })clearComboboxSelection(state)getSelectedIndexCount(selection)getSelectedIndexes(selection)mapSelectedIndexes(selection, map)isIndexSelected(selection, index)
Types:
ComboboxState,ComboboxContext,ComboboxMode
Filter lifecycle
Recommended adapter flow:
- Input change:
state = setComboboxFilter(state, value). - Recompute
filteredOptionsfromstate.filter. - Build
context.optionCount/context.isDisabledfromfilteredOptions. - Run focus/selection operations (
moveComboboxFocus,activateComboboxIndex) with that context. - On clear, run
clearComboboxSelection; close/open remains an explicit adapter decision.
Guaranteed semantics:
setComboboxFiltermutates onlyfilter.setComboboxOpenmutates onlyopen.clearComboboxSelectionclearsfilterand listbox state while preservingopen.
Adapter boundaries
combobox-core handles:
- headless reducer transitions for
open,filter, and listbox state, - mode-dependent behavior (single-mode ignores
toggle/extend), - selection helper derivations (
getSelectedIndexes,mapSelectedIndexes).
Adapter handles:
- rendering and option indexing in DOM,
- actual filtering strategy and async data loading,
- a11y attributes/events and side effects,
- UX policy (open on input, close on selection, keep-open multi-select).
Avoid these pitfalls:
- deriving
optionCountfrom unfiltered data while rendering filtered data, - mutating
state.listbox.selectiondirectly, - mixing implicit close/open behavior into filter changes.
Related packages
@affino/listbox-core@affino/selection-core
Used by adapters
- Laravel runtime: /adapters/laravel
- Vue runtime: /adapters/vue
License
MIT