Управление фокусом в модалах

Управление фокусом является ключевым аспектом доступности модальных окон. Библиотека React Aria предоставляет инструменты для обеспечения правильного поведения фокуса, предотвращения “потери” пользователя внутри интерфейса и соблюдения стандартов WCAG.


Контейнер модального окна и useModal

В React Aria управление модальными окнами начинается с хука useModal. Этот хук позволяет обозначить область как модальную и автоматически блокирует взаимодействие с элементами вне модального окна.

import { useModal } from '@react-aria/overlays';

function ModalContainer(props) {
  let ref = React.useRef();
  let { modalProps } = useModal();

  return (
    <div {...modalProps} ref={ref}>
      {props.children}
    </div>
  );
}

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

  • useModal автоматически управляет атрибутами aria-hidden для элементов вне модального окна.
  • Устанавливает правильный порядок фокуса, чтобы пользователь не мог случайно покинуть модальное окно с клавиатуры.

Управление фокусом внутри модального окна: FocusScope

Хук useFocusScope или компонент <FocusScope> отвечает за изолирование фокуса внутри модального окна. Это предотвращает уход фокуса на элементы, находящиеся под модальным окном.

import { FocusScope } from '@react-aria/focus';

function ModalContent({ children }) {
  return (
    <FocusScope contain restoreFocus autoFocus>
      {children}
    </FocusScope>
  );
}

Опции FocusScope:

  • contain: удерживает фокус внутри области.
  • restoreFocus: возвращает фокус на элемент, который был активен до открытия модального окна.
  • autoFocus: автоматически устанавливает фокус на первый фокусируемый элемент при монтировании.

Автоматическая установка фокуса

React Aria предоставляет механизмы для автоматической фокусировки первого интерактивного элемента. Это часто требуется для кнопок закрытия или полей формы внутри модального окна.

import { useFocus } from '@react-aria/focus';

function CloseButton() {
  let ref = React.useRef();
  let { focusProps } = useFocus({ autoFocus: true });

  return <button {...focusProps} ref={ref}>Закрыть</button>;
}

Параметр autoFocus гарантирует, что элемент станет активным сразу после открытия модального окна, что повышает удобство клавиатурного управления.


Поддержка клавиатурной навигации

Правильное управление фокусом в модальных компонентах невозможно без корректной обработки клавиш Tab и Shift+Tab. Компонент <FocusScope> автоматически циклически перемещает фокус, предотвращая его выход за пределы модального окна.

<FocusScope contain restoreFocus autoFocus>
  <input type="text" placeholder="Имя" />
  <button>Сохранить</button>
</FocusScope>
  • При нажатии Tab фокус переходит на следующий фокусируемый элемент.
  • Если пользователь на последнем элементе нажимает Tab, фокус возвращается на первый элемент.
  • Обратная навигация через Shift+Tab также корректно циклична.

Интеграция с оверлеями

Модальные окна чаще всего реализуются через оверлеи. React Aria предоставляет OverlayProvider и хук useOverlay для безопасного управления фокусом при наложении:

import { OverlayProvider, useOverlay } from '@react-aria/overlays';

function MyModal({ isOpen, onClose, children }) {
  let ref = React.useRef();
  let { overlayProps } = useOverlay({ onClose, isOpen, isDismissable: true }, ref);

  if (!isOpen) return null;

  return (
    <div {...overlayProps} ref={ref}>
      {children}
    </div>
  );
}

// Оборачиваем приложение в OverlayProvider
<OverlayProvider>
  <App />
</OverlayProvider>

Особенности:

  • isDismissable позволяет закрывать модальное окно через клавишу Escape или клики вне окна.
  • useOverlay автоматически работает совместно с FocusScope, обеспечивая безопасный контроль фокуса при открытии и закрытии оверлея.

Возврат фокуса после закрытия

Очень важный аспект доступности — возврат фокуса на элемент, который открыл модальное окно. Опция restoreFocus в FocusScope автоматически сохраняет и восстанавливает предыдущий фокус:

<FocusScope contain restoreFocus autoFocus>
  <ModalContent />
</FocusScope>

Без этой функции пользователь после закрытия модального окна не потеряется и сможет продолжить взаимодействие с интерфейсом с того места, где был до открытия модала.


Рекомендации по практике

  • Всегда использовать <FocusScope contain restoreFocus autoFocus> внутри модального окна.
  • Никогда не блокировать клавиатурный фокус через стили display: none или visibility: hidden — использовать встроенные возможности React Aria.
  • Для сложных форм внутри модальных окон комбинировать FocusScope с useFocus на интерактивных элементах, чтобы гарантировать правильное поведение фокуса.
  • Оборачивать приложение в OverlayProvider, если планируется работа с несколькими оверлеями или модальными окнами одновременно.

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