useSelect
Hook that manages select dropdown state, keyboard navigation, and popup positioning.
Usage#
import { useSelect } from '@primereact/headless/select';const select = useSelect({ options: cities, optionLabel: 'name' });
const { rootProps, triggerProps, listProps, positionerProps, popupProps, arrowProps, state, listbox } = select;useSelect composes useListbox and usePopover internally. See Primitive for a component-based API.
Features#
- Popup lifecycle — open/close state, positioning, focus trap, and Escape/outside-click dismissal
- Listbox integration — option iteration, selection, and keyboard navigation via the returned
listboxinstance - Controlled or uncontrolled — value, popup visibility, and filter text can each be managed externally or internally
- Filtering — dedicated
filterPropsfor a search input inside the popup with locale-aware comparison - Selection modes — single, multiple, and meta-key-based additive selection
- Imperative controls —
show(),hide(),toggle(),focus(),getSelectedOptionLabel(), andhasValue()
Working with callbacks#
Controlled selection#
Pass value and onValueChange to drive the selection from outside state.
const [selected, setSelected] = React.useState(null);
const select = useSelect({
value: selected,
onValueChange: (e) => setSelected(e.value)
});
<div {...rootProps}>
<button {...triggerProps}></button>
<div {...positionerProps}>
<div {...popupProps}>
<ul {...listProps}></ul>
</div>
<div {...arrowProps} />
</div>
</div>;Controlled popup visibility#
Use open with onOpenChange to react to open/close transitions — useful for analytics, coordinating with other overlays, or animating custom wrappers.
const [open, setOpen] = React.useState(false);
const select = useSelect({
options: cities,
optionLabel: 'name',
open,
onOpenChange: (e) => setOpen(e.value)
});Filtering inside the popup#
Render a search input wired through filterProps and drive the query with filterValue / onFilterValueChange.
const [filterValue, setFilterValue] = React.useState('');
const select = useSelect({
options: cities,
optionLabel: 'name',
filterValue,
onFilterValueChange: (e) => setFilterValue(e.query)
});
<input {...select.filterProps} placeholder="Search..." />;Object options with grouping#
Map object fields with optionLabel, optionValue, optionDisabled, and optionKey; add optionGroupLabel / optionGroupChildren for grouped structures.
const select = useSelect({
options: groupedCities,
optionLabel: 'label',
optionValue: 'code',
optionDisabled: 'inactive',
optionKey: 'code',
optionGroupLabel: 'label',
optionGroupChildren: 'items'
});Multiple selection with meta key#
Combine multiple and metaKeySelection to require Cmd/Ctrl for additive selection — matching native multi-select semantics.
const select = useSelect({ multiple: true, metaKeySelection: true });Styling with data attributes#
The hook exposes state through data-* attributes on each part. Use them as CSS selectors — no className juggling.
| Scope | Part | States |
|---|---|---|
select | trigger | data-positioner-open |
select | popup | data-open |
select | indicator | data-open, data-closed |
listbox | option | data-selected, data-unselected, data-focused, data-disabled |
listbox | optionindicator | data-selected, data-unselected |
[data-scope='select'][data-part='trigger']:focus-visible {
outline: 2px solid var(--p-primary-color);
outline-offset: -2px;
}
[data-scope='select'][data-part='indicator'][data-open] {
transform: rotate(180deg);
}
[data-scope='select'][data-part='popup'][data-open] {
border: 1px solid var(--p-content-border-color);
border-radius: 6px;
box-shadow: 0 4px 12px rgb(0 0 0 / 0.1);
}
[data-scope='listbox'][data-part='option'][data-focused] {
background: var(--p-surface-100);
}
[data-scope='listbox'][data-part='option'][data-selected] {
background: var(--p-primary-color);
color: var(--p-primary-contrast-color);
}API#
useSelect#
| Name | Type | Default |
|---|---|---|
value | unknown | — |
| The current selected value of the select. | ||
defaultValue | unknown | — |
| The default selected value when used in uncontrolled mode. | ||
filterValue | string | — |
| The current filter text value (controlled). | ||
defaultFilterValue | string | — |
| The default filter text value when used in uncontrolled mode. | ||
open | boolean | — |
| Controlled open state of the select overlay. | ||
defaultOpen | boolean | — |
| Default open state for uncontrolled mode. | ||
options | unknown[] | — |
| An array of options to display. | ||
optionKey | string | — |
| Unique key for each option. | ||
optionLabel | string | — |
| Label field for each option. | ||
optionValue | string | — |
| Value field for each option. | ||
optionDisabled | string | — |
| Field to check if an option is disabled. | ||
optionGroupLabel | string | — |
| Label field for option groups. | ||
optionGroupChildren | string | — |
| Field that contains the children options in a group. | ||
disabled | boolean | — |
| When present, it specifies that the component should be disabled. | ||
locale | string | — |
| The locale to use for localization. | ||
autoOptionFocus | boolean | — |
| When enabled, the focused option is automatically highlighted. | ||
selectOnFocus | boolean | — |
| When enabled, the focused option is automatically selected. | ||
focusOnHover | boolean | — |
| When enabled, the focused option changes on hover. | ||
metaKeySelection | boolean | — |
| When enabled, requires holding the meta key to select/deselect. | ||
multiple | boolean | — |
| When enabled, allows multiple items to be selected. | ||
filter | boolean | — |
| When enabled, displays a filter input in the dropdown. | ||
filterMatchMode | "endsWith" | "startsWith" | "contains" | "equals" | — |
| Defines how the filter should match options. | ||
appendTo | "body" | HTMLElement | "self" | — |
| A valid query selector or an HTMLElement to specify where the overlay gets attached. | ||
tabIndex | number | — |
| Index of the element in tabbing order. | ||
invalid | boolean | — |
| When present, it specifies that the component is in an invalid state. | ||
ariaLabel | string | — |
| Used to define a string that labels the input element. | ||
ariaLabelledBy | string | — |
| Identifier of the underlying input element. | ||
closeOnEscape | boolean | — |
| When enabled, the overlay closes when Escape key is pressed. | ||
autoFocus | boolean | — |
| When enabled, the overlay receives focus automatically when opened. | ||
trapped | boolean | — |
| When enabled, focus is trapped within the overlay. | ||
onValueChange | (event: useSelectValueChangeEvent) => void | — |
| Callback to invoke when the selected value changes. | ||
onFilterValueChange | (event: useSelectFilterValueChangeEvent) => void | — |
| Callback when the filter value changes. | ||
onOpenChange | (event: useSelectOpenChangeEvent) => void | — |
| Callback to invoke when the open state changes. | ||
Accessibility#
Arrow keys move focus through options, Enter or Space selects, Home/End jump to first/last, and type-ahead search matches by label. See Primitive for full WAI-ARIA compliance details.