React Aria предоставляет мощные инструменты для создания доступных
интерфейсов с использованием JavaScript и React. Одной из ключевых задач
при работе с компонентами выбора, такими как Select или
ListBox, является корректная группировка
опций для улучшения навигации и восприятия пользователем.
Группировка опций позволяет логически объединять элементы списка,
облегчая поиск и понимание их структуры.
В React Aria группы опций представляются объектами с полями
type, name и children.
Стандартная структура выглядит следующим образом:
const options = [
{
type: 'section',
name: 'Фрукты',
children: [
{ type: 'item', name: 'Яблоко' },
{ type: 'item', name: 'Банан' },
{ type: 'item', name: 'Апельсин' }
]
},
{
type: 'section',
name: 'Овощи',
children: [
{ type: 'item', name: 'Морковь' },
{ type: 'item', name: 'Брокколи' },
{ type: 'item', name: 'Перец' }
]
}
];
type: 'section' обозначает группу элементов.name — это название группы, которое будет отображаться
пользователю.children — массив элементов внутри группы, каждый с
типом item.Такая структура обеспечивает совместимость с компонентами React Aria и позволяет использовать их встроенные механизмы доступности.
useListBox и useListBoxSectionДля реализации списка с группами опций React Aria предоставляет хуки
useListBox и useListBoxSection.
import { useListBox, useListBoxSection } from '@react-aria/listbox';
import { useTreeState } from '@react-stately/tree';
function MyListBox({ options }) {
const state = useTreeState({ items: options });
return (
<ul {...useListBox({ selectionMode: 'single' }, state)}>
{state.collection.map((item) =>
item.type === 'section' ? (
<ListBoxSection key={item.key} section={item} />
) : (
<ListBoxItem key={item.key} item={item} />
)
)}
</ul>
);
}
function ListBoxSection({ section }) {
const { itemProps, headingProps, groupProps } = useListBoxSection({ section });
return (
<li {...groupProps}>
<div {...headingProps}>{section.name}</div>
<ul>
{section.children.map((item) => (
<ListBoxItem key={item.key} item={item} />
))}
</ul>
</li>
);
}
function ListBoxItem({ item }) {
return <li>{item.name}</li>;
}
Ключевые моменты:
useTreeState формирует состояние коллекции с поддержкой
разделов и элементов.useListBoxSection автоматически добавляет необходимые
атрибуты для заголовков и групп, включая aria-labelledby и
role="group".key,
что важно для корректного рендеринга в React.React Aria автоматически обрабатывает навигацию с клавиатуры для списков с секциями. Пользователь может:
Home и
End.aria-labelledby и
семантических ролей (group и listbox).Группировка обеспечивает правильную работу скринридеров и улучшает восприятие контента пользователями с ограниченными возможностями.
React Aria поддерживает вложенные группы, позволяя создавать многоуровневые списки:
const nestedOptions = [
{
type: 'section',
name: 'Континенты',
children: [
{
type: 'section',
name: 'Европа',
children: [
{ type: 'item', name: 'Франция' },
{ type: 'item', name: 'Германия' }
]
},
{
type: 'section',
name: 'Азия',
children: [
{ type: 'item', name: 'Япония' },
{ type: 'item', name: 'Китай' }
]
}
]
}
];
Использование вложенных групп аналогично одноуровневым секциям, важно
лишь корректно обрабатывать children при рендеринге с
useListBoxSection.
React Aria не навязывает визуальное оформление, поэтому для групп можно применять собственные стили:
li[group] > div {
font-weight: bold;
margin-top: 1em;
color: #333;
}
li[item] {
padding: 4px 8px;
}
Это позволяет создавать списки с визуальной иерархией, которая соответствует логике группировки.
Состояние коллекции можно обновлять динамически:
state.insertItem({ type: 'item', name: 'Груша' }, state.collection.get('Фрукты'));
state.removeItem(state.collection.get('Брокколи'));
React Aria автоматически обновляет рендер и навигацию, сохраняя доступность.
type: 'section' для всех групп.key элементам и
секциям.section → item для
корректной работы скринридеров.children и
aria-атрибуты.Группировка опций в React Aria является важной частью создания
интерфейсов, которые одновременно логичны, удобны и
доступны. Корректная структура данных, использование хуков
useListBox и useListBoxSection, а также
внимание к доступности обеспечивают надежный и масштабируемый
пользовательский опыт.