Навигация по двумерной структуре

React Aria предоставляет набор хуков и утилит для управления доступностью интерфейсов. Одной из ключевых задач при работе с компонентами типа таблиц, сеток, календарей или списков с вложенными элементами является двумерная навигация. Она позволяет пользователю перемещаться по элементам с помощью клавиатуры, обеспечивая полноценный контроль и соответствие стандартам ARIA.


Управление фокусом с useGrid и useGridCell

В React Aria двумерная структура представляется через сетку (grid). Хук useGrid отвечает за всю сетку целиком, а useGridCell — за отдельные ячейки.

Пример использования сетки:

import { useGrid, useGridCell } from '@react-aria/grid';
import { useGridState } from '@react-stately/grid';
import { useFocusRing } from '@react-aria/focus';

function Grid({ items, columns }) {
  let state = useGridState({ 
    selectionMode: 'single',
    collection: items,
    columnCount: columns
  });

  let { gridProps } = useGrid({}, state);

  return (
    <div {...gridProps} role="grid">
      {state.collection.map((row) => (
        <div role="row" key={row.key}>
          {row.childNodes.map((cell) => (
            <GridCell key={cell.key} cell={cell} state={state} />
          ))}
        </div>
      ))}
    </div>
  );
}

function GridCell({ cell, state }) {
  let ref = React.useRef();
  let { gridCellProps } = useGridCell({ node: cell }, state);
  let { isFocusVisible, focusProps } = useFocusRing();

  return (
    <div
      {...gridCellProps}
      {...focusProps}
      ref={ref}
      style={{
        outline: isFocusVisible ? '2px solid blue' : 'none',
        padding: 8,
        border: '1px solid gray'
      }}
    >
      {cell.rendered}
    </div>
  );
}

Ключевые моменты:

  • useGrid управляет состоянием сетки и поддерживает навигацию стрелками.
  • useGridCell обеспечивает правильное управление фокусом на уровне ячеек.
  • useFocusRing позволяет визуально отображать фокус, соответствующий стандартам WCAG.

Состояние сетки с useGridState

useGridState предоставляет состояние сетки, включая выделение и фокус. Основные параметры:

  • selectionMode: 'none' | 'single' | 'multiple'.
  • collection: массив данных для отображения.
  • columnCount: количество колонок, используемое для вычисления позиции фокуса.

Состояние управляет логикой перехода между ячейками при нажатии стрелок вверх, вниз, влево и вправо. React Aria автоматически определяет следующую ячейку, учитывая видимые и активные элементы.


Навигация с клавиатуры

React Aria реализует интеллектуальную обработку клавиатуры:

  • Стрелки влево/вправо перемещают фокус по колонкам.
  • Стрелки вверх/вниз перемещают фокус по строкам.
  • Home/End переводят фокус на начало или конец строки.
  • PageUp/PageDown при больших сетках могут прокручивать страницу и переводить фокус.

Это позволяет создавать полностью доступные таблицы и сетки без дополнительной ручной логики.


Поддержка выделения ячеек и строк

React Aria предоставляет удобные хуки для работы с выделением:

  • state.selectionManager — управление выбранными элементами.
  • state.setSelectedKeys(keys) — изменение выделения.

Выделение может быть как по ячейкам, так и по строкам, в зависимости от конфигурации selectionMode. Для многократного выбора можно использовать комбинации с Shift и Ctrl, которые React Aria обрабатывает автоматически.


Интеграция с ARIA атрибутами

Для соблюдения стандартов доступности сетки автоматически назначаются ARIA-атрибуты:

  • role="grid" для контейнера сетки.
  • role="row" для строк.
  • role="gridcell" для ячеек.
  • aria-selected для выбранных элементов.
  • tabIndex для управления фокусом.

Это обеспечивает полную совместимость с экранными читалками и поддерживает навигацию клавиатурой без дополнительного кода.


Оптимизация производительности

Для больших сеток важно минимизировать ререндеринг:

  • Использовать React.memo для отдельных ячеек.
  • Вычислять коллекцию через useMemo при изменении данных.
  • Ограничивать количество активных ячеек на экране с виртуализацией (react-virtual или react-virtualized).

Настройка кастомной навигации

React Aria позволяет переопределять стандартную логику перемещения фокуса с помощью опций focusMode и onAction:

let { gridProps } = useGrid({
  onAction: (key) => console.log(`Активирован элемент ${key}`),
  focusMode: 'cell' // 'row' или 'cell'
}, state);

Это дает возможность реализовать:

  • Навигацию по блокам (например, объединённые ячейки).
  • Пропуск определённых элементов.
  • Специальные действия при фокусе на ячейке.

Важные практики

  • Всегда использовать role и aria-* атрибуты для совместимости с ассистивными технологиями.
  • Разделять визуальное состояние и состояние фокуса для обеспечения предсказуемости интерфейса.
  • Обрабатывать все клавиатурные события через хуки React Aria, а не напрямую через onKeyDown.
  • Применять виртуализацию для больших сеток для снижения нагрузки на DOM.

Навигация по двумерной структуре в React Aria обеспечивает интуитивное управление, доступность и согласованность поведения, делая таблицы и сетки полностью пригодными для профессиональных веб-приложений.