React Aria предоставляет набор хуков и утилит для создания доступных интерфейсов, в которых навигация с клавиатуры реализуется на профессиональном уровне. Основная цель — позволить пользователям перемещаться по компонентам без мыши, обеспечивая полное соответствие стандартам доступности (WCAG) и лучшим практикам ARIA.
useFocusRing — ключевой хук для
управления визуальными индикаторами фокуса. Он позволяет отслеживать,
находится ли элемент в фокусе, и автоматически добавлять классы для
стилизации:
import { useFocusRing } from '@react-aria/focus';
function FocusableButton(props) {
let { isFocusVisible, focusProps } = useFocusRing();
return (
<button {...focusProps} className={isFocusVisible ? 'focus-visible' : ''}>
{props.children}
</button>
);
}
Особенности useFocusRing:
useFocus — обеспечивает базовое
управление фокусом без визуальных индикаторов. Применяется для
компонентов, где необходим контроль фокуса программно.
import { useFocus } from '@react-aria/interactions';
function CustomInput(props) {
let { focusProps } = useFocus();
return <input {...focusProps} {...props} />;
}
Для реализации доступной навигации внутри списков, табов,
меню и селектов используются хуки useListBox,
useMenu, useMenuTrigger. Они обеспечивают
управление фокусом и правильное реагирование на клавиши стрелок, Home,
End, Enter и Escape.
Пример: управление списком с клавиатуры
import { useListBox, useOption } from '@react-aria/listbox';
import { useListState } from '@react-stately/list';
function SelectList({ items }) {
let state = useListState({ items });
let ref = React.useRef();
let { listBoxProps } = useListBox({ autoFocus: true }, 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} className={`${isFocused ? 'focused' : ''} ${isSelected ? 'selected' : ''}`}>
{item.rendered}
</li>
);
}
Ключевые моменты:
useListState управляет состоянием выбранных и активных
элементов.React Aria поддерживает работу с клавишами Shift, Ctrl, Alt и Meta. Для множественного выбора в списках применяются комбинации с Shift или Ctrl. Хуки обеспечивают правильное добавление атрибутов ARIA:
<li
role="option"
aria-selected={isSelected}
onKeyD own={e => {
if (e.shiftKey && e.key === 'ArrowDown') {
// расширяем выделение
}
}}
>
{item.name}
</li>
tabIndex={0} используется для элементов, доступных
через Tab.tabIndex={-1} позволяет программно переводить фокус без
попадания в обычный порядок табуляции.useFocus,
useListBox) обеспечивает согласованное поведение и
корректную поддержку скринридеров.Модальные окна и всплывающие элементы требуют замыкания
фокуса внутри компонента. React Aria предоставляет хук
useOverlay, который автоматически
блокирует фокус на фоне и позволяет перемещаться только между
интерактивными элементами внутри оверлея:
import { useOverlay } from '@react-aria/overlays';
function Modal({ isOpen, onClose, children }) {
let ref = React.useRef();
let { overlayProps } = useOverlay({ isOpen, onClose, isDismissable: true }, ref);
if (!isOpen) return null;
return (
<div {...overlayProps} ref={ref} className="modal">
{children}
</div>
);
}
Особенности:
aria-selected — выделение элементов списка или
меню.aria-expanded — раскрытие и сворачивание меню.aria-haspopup — наличие всплывающего меню.aria-activedescendant — управление активным элементом
для списков без прямого фокуса на каждом элементе.Использование этих атрибутов совместно с хуками React Aria гарантирует правильное поведение при навигации с клавиатуры.
useListState и useOption.useOverlay с
замыканием фокуса.Эта комбинация хуков и правильного применения атрибутов обеспечивает полное соответствие стандартам доступности и удобную клавиатурную навигацию в React-приложениях.