React Aria предоставляет мощный набор хуков для создания интерфейсов с доступностью, включая функциональность drag and drop. Основной принцип заключается в том, чтобы разделить логику управления состоянием и поведение элементов от их визуального представления, что позволяет обеспечить поддержку клавиатуры, экранных читалок и других ассистивных технологий.
Для управления состоянием перетаскивания используется хук
useDragAndDrop, который инкапсулирует логику определения
источников и целей перетаскивания. Он возвращает объект состояния с
полями:
isDragging — булевый флаг, определяющий, выполняется ли
текущая операция перетаскивания.draggedItem — объект с данными перетаскиваемого
элемента.overItem — элемент, над которым находится курсор или
фокус при перетаскивании.Пример инициализации:
import {useDragAndDrop} from '@react-aria/dnd';
import {useState} from 'react';
function DndContainer({items}) {
const [state, setState] = useState(items);
const {dragProps, dropProps, isDragging} = useDragAndDrop({items, onMove: handleMove});
function handleMove(fromIndex, toIndex) {
const updated = [...state];
const [moved] = updated.splice(fromIndex, 1);
updated.splice(toIndex, 0, moved);
setState(updated);
}
return (
<div {...dropProps}>
{state.map((item, index) => (
<div key={item.id} {...dragProps(item)}>
{item.name}
</div>
))}
</div>
);
}
React Aria автоматически добавляет ARIA-атрибуты и события клавиатуры, но важно правильно структурировать DOM. Каждый элемент должен иметь:
tabIndex={0} для фокусируемости;role="listitem" для обозначения элемента списка;aria-grabbed для индикации, что элемент может быть
перемещен;aria-dropeffect на контейнере, чтобы обозначить
возможность сброса.Пример применения:
<div
role="list"
{...dropProps}
>
{items.map(item => (
<div
role="listitem"
tabIndex={0}
aria-grabbed={isDragging && draggedItem.id === item.id}
key={item.id}
{...dragProps(item)}
>
{item.name}
</div>
))}
</div>
С помощью этих атрибутов экранные читалки корректно сообщают пользователю о состоянии drag and drop, включая выбор и положение элементов.
Для повышения доступности важно предоставлять наглядные подсказки о состоянии перетаскивания:
dragging для выделения
перемещаемого элемента;drop target при наведении;React Aria позволяет связывать состояние и визуальное представление через хуки, без вмешательства в логику событий. Например:
<div
className={`item ${isDragging && draggedItem.id === item.id ? 'dragging' : ''}`}
{...dragProps(item)}
>
{item.name}
</div>
React Aria поддерживает как нативные события HTML5, так и клавиатурные аналоги. Основные события:
onDragStart — инициализация перетаскивания, установка
состояния draggedItem;onDragOver — проверка возможности сброса;onDrop — завершение операции и вызов
onMove;onDragEnd — очистка состояния и снятие визуальных
индикаторов.Для клавиатурного взаимодействия используются:
React Aria генерирует ARIA-атрибуты, но правильная структура DOM критична:
role="list";role="listitem", с атрибутом
aria-grabbed;useMove для сложных
сценариев, где требуется анимация и сортировка элементов.aria-grabbed и
aria-dropeffect.React Aria позволяет интегрировать drag and drop с любыми визуальными библиотеками:
dragProps и dropProps в обертку
компонента;useRef для контроля DOM-элементов;Пример интеграции с компонентом карточки:
function Card({item, dragProps}) {
return (
<div className="card" {...dragProps(item)}>
<h3>{item.title}</h3>
<p>{item.description}</p>
</div>
);
}
Использование хуков React Aria обеспечивает максимальную совместимость с ассистивными технологиями при сохранении гибкости интерфейса и возможности кастомизации визуального оформления.