Хук useSelectableList из библиотеки React Aria
предназначен для организации доступных, управляемых списков с поддержкой
выделения элементов. Он обеспечивает корректное взаимодействие с
клавиатурой, мышью и вспомогательными технологиями (screen readers), а
также интеграцию с состоянием списка.
import { useSelectableList } from '@react-aria/listbox';
import { useListState } from '@react-stately/list';
Для начала работы необходимо создать состояние списка с помощью
useListState. Оно управляет коллекцией элементов,
выбранными элементами и текущим фокусом. Затем хук
useSelectableList связывает это состояние с
DOM-элементами.
const state = useListState({ selectionMode: 'single', items: myItems });
const ref = useRef();
const { listProps, selectionManager } = useSelectableList({ selectionMode: 'single' }, state, ref);
role, aria-*), которые нужно
развернуть на корневом элементе.Хук принимает три аргумента:
props – настройки списка:
selectionMode –
'none' | 'single' | 'multiple'. Определяет, может ли
пользователь выбирать элементы и сколько.disabledKeys – массив ключей элементов, которые нельзя
выбирать.onSelectionChange – коллбэк, вызываемый при изменении
выбора.state – объект состояния списка, создаваемый
useListState.
ref – ref на контейнер списка,
необходимый для правильного управления фокусом и событиями.
Каждый элемент списка должен иметь уникальный key. React
Aria использует этот ключ для отслеживания выделения и навигации.
Элементы можно рендерить с помощью метода
state.collection.map:
<ul {...listProps} ref={ref}>
{state.collection.map((item) => (
<li
key={item.key}
{...item.props}
aria-selected={state.selectionManager.isSelected(item.key)}
>
{item.rendered}
</li>
))}
</ul>
item.props содержит атрибуты для обеспечения правильной
доступности и взаимодействия.selectionManager предоставляет методы:
isSelected(key) – проверяет, выбран ли элемент.select(key) – выделяет элемент (заменяет текущее
выделение в режиме 'single' или добавляет в
'multiple').toggleSelection(key) – переключает состояние элемента в
режиме 'multiple'.clearSelection() – снимает выделение со всех
элементов.setFocusedKey(key) – устанавливает фокус на конкретный
элемент.Использование этих методов позволяет программно управлять выбором и фокусом.
const handleClick = (key) => {
selectionManager.toggleSelection(key);
selectionManager.setFocusedKey(key);
};
useSelectableList автоматически обрабатывает:
Важно обеспечить правильное применение listProps и
item.props, чтобы клавиатурная навигация работала
корректно.
Списки не обязательно должны быть
<ul>/<li>. Любой контейнер и
элементы можно использовать, главное – корректно развернуть
listProps и item.props. Пример кастомного
компонента:
<div {...listProps} ref={ref} className="custom-list">
{state.collection.map((item) => (
<div
key={item.key}
{...item.props}
className={`custom-item ${selectionManager.isSelected(item.key) ? 'selected' : ''}`}
>
{item.rendered}
</div>
))}
</div>
Для множественного выбора можно использовать
selectionMode: 'multiple'. В этом случае
selectionManager.toggleSelection(key) позволяет добавлять
или удалять элементы из текущего выделения.
onSelectionChange получает массив выбранных ключей:
const state = useListState({
selectionMode: 'multiple',
items: myItems,
onSelectionChange: (keys) => console.log(keys),
});
key.state.collection.useSelectableList без состояния
useListState, иначе функционал выделения и фокуса не будет
работать.aria-* атрибуты, предоставляемые хуком.useSelectableList позволяет создавать списки, полностью
совместимые с WAI-ARIA, поддерживающие клавиатуру, мышь и доступные для
ассистивных технологий. Комбинируя его с useListState,
можно построить гибкие интерфейсы с одиночным или множественным
выделением, полностью управляемые и кастомизируемые.