Библиотека React Aria предоставляет инструменты для управления поведением интерактивных компонентов с акцентом на доступность. Одним из ключевых аспектов является корректная реализация закрытия модальных окон, всплывающих панелей и других интерактивных элементов при нажатии клавиши Escape или клике вне компонента.
В React Aria для обработки клавиш используется хук useKeyboard или специализированные хуки, такие как useOverlay. Основная идея заключается в том, чтобы слушать события клавиатуры на уровне компонента и реагировать на конкретные клавиши.
Пример использования:
import {useOverlay, usePreventScroll} from '@react-aria/overlays';
import {useRef} from 'react';
function Modal({isOpen, onClose, children}) {
const ref = useRef();
usePreventScroll(); // предотвращает скролл фона при открытом модальном окне
const {overlayProps, underlayProps} = useOverlay(
{
isOpen,
onClose,
isDismissable: true, // включает закрытие по Escape и клику вне
},
ref
);
return isOpen ? (
{children}
) : null;
}
Ключевой момент: свойство isDismissable: true автоматически добавляет обработку закрытия по клавише Escape и клику вне компонента. Это освобождает от необходимости вручную подписываться на события клавиатуры или клика.
Для реализации закрытия при клике вне компонента используется тот же хук useOverlay. React Aria отслеживает клики по документу и сравнивает целевой элемент с корневым элементом оверлея. Если клик произошёл вне, вызывается функция onClose.
Особенности:
Если нужно более тонкое управление кликами, можно комбинировать useOverlayTrigger и useOverlay для управления состоянием:
import {useOverlayTriggerState} from '@react-stately/overlays';
import {useOverlayTrigger, useOverlay} from '@react-aria/overlays';
import {useRef} from 'react';
function Dropdown() {
const state = useOverlayTriggerState({});
const triggerRef = useRef();
const overlayRef = useRef();
const {triggerProps, overlayProps} = useOverlayTrigger(
{type: 'menu'},
state,
triggerRef
);
const {overlayProps: overlayEvents} = useOverlay(
{isOpen: state.isOpen, onClose: state.close, isDismissable: true},
overlayRef
);
return (
<>
{state.isOpen && (
Пункт 1
Пункт 2
)}
>
);
}
Здесь isDismissable: true объединяет обработку Escape и кликов вне, а useOverlayTriggerState управляет состоянием открытого меню.
При закрытии оверлея важно вернуть фокус на элемент, вызвавший его открытие. React Aria делает это автоматически, если используется useOverlayTriggerState совместно с useOverlayTrigger. Фокусирование выполняется корректно даже при закрытии через Escape или клик вне.
Дополнительные рекомендации:
React Aria позволяет легко сочетать оверлеи с компонентами типа Dialog, Tooltip, Menu:
Сочетание хуков useOverlay, useOverlayTrigger, useOverlayTriggerState обеспечивает универсальный подход для всех этих компонентов.