useListBox — это хук из библиотеки React
Aria, предназначенный для управления списками опций в
компонентах интерфейса, таких как выпадающие меню, селекты и списки с
поддержкой клавиатуры. Он обеспечивает доступность (accessibility) на
уровне WAI-ARIA, автоматически добавляя необходимые атрибуты и события
для взаимодействия с экранными считывателями и клавиатурой.
Хук не отвечает за визуальное отображение компонентов: он предоставляет свойства и обработчики, которые нужно передать корневому элементу списка и элементам опций, обеспечивая правильное управление фокусом, выделением и навигацией.
Для начала требуется импортировать необходимые хуки и типы из React Aria и React Stately:
import { useListBox, useOption } from '@react-aria/listbox';
import { useListState } from '@react-stately/list';
useListState управляет внутренним состоянием списка:
выбранные элементы, фокус, состояние disabled и прочее.
useListBox использует это состояние для генерации атрибутов
ARIA.
Простейший пример базового списка:
function ListBoxExample(props) {
let state = useListState(props);
let ref = React.useRef();
let { listBoxProps } = useListBox(props, state, ref);
return (
<ul {...listBoxProps} ref={ref}>
{[...state.collection].map(item => (
<Option key={item.key} item={item} state={state} />
))}
</ul>
);
}
function Option({ item, state }) {
let ref = React.useRef();
let { optionProps, isSelected, isFocused } = useOption({ key: item.key }, state, ref);
return (
<li
{...optionProps}
ref={ref}
style={{
background: isFocused ? 'lightblue' : 'transparent',
fontWeight: isSelected ? 'bold' : 'normal',
}}
>
{item.rendered}
</li>
);
}
Ключевые моменты:
listBoxProps содержит все необходимые атрибуты ARIA
(role="listbox", aria-multiselectable,
обработчики клавиатуры).optionProps — атрибуты для каждой опции
(role="option", aria-selected,
aria-disabled).isFocused и isSelected позволяет
управлять визуальной подсветкой и стилями.useListBox автоматически интегрируется с клавиатурной
навигацией:
При этом разработчик не должен вручную писать обработчики клавиатуры
— достаточно передать listBoxProps корневому элементу
списка.
Для списков с множественным выбором используется
selectionMode: "multiple" при инициализации состояния:
let state = useListState({
selectionMode: 'multiple',
items: ['Яблоко', 'Банан', 'Груша']
});
В таком режиме useOption автоматически обрабатывает
выделение нескольких элементов и выставляет aria-selected
корректно для каждой опции.
Опции и группы можно помечать как disabled:
let items = [
{ name: 'Фрукты', key: 'fruits', children: [
{ name: 'Яблоко', key: 'apple', isDisabled: false },
{ name: 'Банан', key: 'banana', isDisabled: true }
]}
];
useOption установит aria-disabled="true"
для опций с isDisabled: true, что предотвратит выбор таких
элементов и корректно сообщит об этом экранным считывателям.
Для групп можно использовать role="group" и
aria-labelledby, что поддерживается в коллекциях
React Stately.
useListBox и useOption не навязывают
визуальные решения. Стиль и анимации полностью на стороне разработчика.
Можно использовать условные стили для:
isSelected)isFocused)isDisabled)Пример стилизации:
style={{
padding: '8px 12px',
cursor: isDisabled ? 'not-allowed' : 'pointer',
background: isFocused ? '#e0f7ff' : 'transparent',
color: isDisabled ? '#aaa' : '#000',
}}
Для длинных списков часто используют виртуализацию через
react-virtual или react-window. В этом случае
useListBox продолжает корректно управлять фокусом и
выделением, если опции рендерятся динамически, потому что все вычисления
состояния происходят через useListState.
useListBox автоматически добавляет атрибуты ARIA:
role="listbox" на корневой элемент.aria-multiselectable="true/false" для множественного
выбора.role="option" на каждой опции.aria-selected для выбранных элементов.aria-disabled для недоступных опций.aria-activedescendant.Это позволяет создавать полностью доступные списки без ручного вмешательства.
useListBox можно комбинировать с:
useListState и ререндерим список.items коллекции.useOverlay.useListBox в связке с useOption и
useListState предоставляет мощный, гибкий и доступный
способ работы с интерактивными списками в React, освобождая от
необходимости вручную управлять фокусом, выделением и атрибутами ARIA.
Такой подход гарантирует совместимость с клавиатурой, экранными
считывателями и различными сценариями сложного UI.