Хук useComboBox является ключевым инструментом для создания доступных комбобоксов в приложениях на React. Он обеспечивает правильное управление фокусом, клавиатурными событиями, взаимодействие с пользователем и интеграцию с доступностью (ARIA) без необходимости ручного написания всей логики.
Для использования хука необходимо подключить его из пакета @react-aria/combobox:
import { useComboBox } from '@react-aria/combobox';
import { useComboBoxState } from '@react-stately/combobox';
import { useButton } from '@react-aria/button';
import { useListBox } from '@react-aria/listbox';
import { useOverlay, useOverlayPosition } from '@react-aria/overlays';
Типичный комбобокс состоит из:
Хук useComboBox объединяет состояние, управление событиями и ARIA-атрибуты, чтобы все компоненты работали корректно вместе.
Состояние комбобокса управляется через useComboBoxState из React Stately:
const state = useComboBoxState({
items: ['Apple', 'Banana', 'Cherry', 'Date'],
defaultFilter: 'startsWith', // фильтрация опций по началу текста
allowsCustomValue: false // разрешить ввод только из списка
});
Ключевые свойства состояния:
const { inputProps, listBoxProps, labelProps, buttonProps } = useComboBox({
inputRef,
buttonRef,
listBoxRef,
popoverRef
}, state);
Пример поля ввода:
<input {...inputProps} ref={inputRef} />
<button {...buttonProps} ref={buttonRef} aria-label="Выбрать опцию">
▼
</button>
Кнопка синхронизируется с состоянием через state.toggleOpen(). Хук автоматически добавляет обработку клавиатуры (Enter, Space) и поддержку экранных читалок.
Список опций размещается внутри Overlay для правильного позиционирования:
import { Overlay, OverlayContainer } from '@react-aria/overlays';
<OverlayContainer>
{state.isOpen && (
<Overlay {...overlayProps} ref={popoverRef}>
<ul {...listBoxProps} ref={listBoxRef}>
{state.collection.map((item) => (
<li key={item.key} {...item.props}>
{item.rendered}
</li>
))}
</ul>
</Overlay>
)}
</OverlayContainer>
Хук useComboBox обрабатывает стандартные клавиши:
Для кастомизации можно использовать дополнительные обработчики через
onKeyDown.
С помощью React Stately можно легко интегрировать динамические источники данных:
const state = useComboBoxState({
items: asyncItems, // массив, получаемый через API
defaultFilter: (textValue, item) => item.startsWith(textValue),
});
Фильтрация обновляет state.collection, автоматически изменяя доступные опции в списке.
useComboBox автоматически добавляет необходимые атрибуты:
role="combobox" для контейнера.aria-expanded для состояния открытия.aria-controls и aria-labelledby для связи
поля ввода с списком и меткой.aria-activedescendant для подсветки выбранной
опции.input, manual).function FruitComboBox() {
const inputRef = useRef();
const buttonRef = useRef();
const listBoxRef = useRef();
const popoverRef = useRef();
const state = useComboBoxState({
items: ['Apple', 'Banana', 'Cherry', 'Date'],
allowsCustomValue: false
});
const { inputProps, listBoxProps, labelProps, buttonProps } = useComboBox({
inputRef,
buttonRef,
listBoxRef,
popoverRef
}, state);
return (
<div>
<label {...labelProps}>Фрукты</label>
<div style={{ display: 'flex' }}>
<input {...inputProps} ref={inputRef} />
<button {...buttonProps} ref={buttonRef}>▼</button>
</div>
{state.isOpen && (
<div ref={popoverRef}>
<ul {...listBoxProps} ref={listBoxRef}>
{state.collection.map(item => (
<li key={item.key} {...item.props}>{item.rendered}</li>
))}
</ul>
</div>
)}
</div>
);
}
Этот пример демонстрирует правильное взаимодействие всех частей комбобокса: состояния, поля ввода, кнопки и выпадающего списка с поддержкой клавиатуры и ARIA.
react-virtual или аналогичные библиотеки.setInputValue в рендере,
использовать события ввода (onInputChange).Хук useComboBox обеспечивает полную готовую к использованию архитектуру комбобоксов, позволяя создавать сложные компоненты с доступностью, динамическими данными и поддержкой клавиатуры без написания повторяющейся логики вручную.