focus-trap — это библиотека на JavaScript,
обеспечивающая управление фокусом внутри заданной области DOM. Она
используется для модальных окон, всплывающих панелей, диалогов и других
интерактивных элементов, где важно ограничить фокус только внутри
компонента до его закрытия. Главная цель — предотвращение ухода фокуса
пользователя за пределы активного интерактивного элемента, что критично
для доступности.
Основной принцип работы заключается в перехвате событий
Tab и Shift+Tab и циклическом перемещении
фокуса между фокусируемыми элементами внутри контейнера. Библиотека
предоставляет API для активации и деактивации «ловушки фокуса», а также
настройки поведения при открытии и закрытии компонента.
Для подключения используется npm:
npm install focus-trap
Импорт в проект:
import { createFocusTrap } from 'focus-trap';
createFocusTrap возвращает объект с методами
activate, deactivate, pause и
unpause, что позволяет гибко управлять состоянием
фокуса.
Простейший пример создания фокус-трапа для модального окна:
const modal = document.getElementById('modal');
const focusTrap = createFocusTrap(modal, {
onActivate: () => modal.classList.add('is-active'),
onDeactivate: () => modal.classList.remove('is-active'),
});
document.getElementById('openBtn').addEventListener('click', () => focusTrap.activate());
document.getElementById('closeBtn').addEventListener('click', () => focusTrap.deactivate());
Ключевые моменты:
onActivate вызывается при активации ловушки, что удобно
для добавления стилей.onDeactivate срабатывает при выходе из ловушки,
возвращая состояние интерфейса.activate автоматически переводит фокус на первый
фокусируемый элемент внутри контейнера.Focus-trap поддерживает несколько опций для тонкой настройки:
initialFocus: '#firstInput'
Escape.Пример расширенной конфигурации:
const focusTrap = createFocusTrap(modal, {
initialFocus: () => document.getElementById('firstInput'),
fallbackFocus: modal,
escapeDeactivates: true,
clickOutsideDeactivates: true,
returnFocusOnDeactivate: true,
});
В сложных интерфейсах, где элементы рендерятся динамически, важно
использовать activate после полной загрузки DOM внутри
модального окна:
async function openModal() {
await renderModalContent();
focusTrap.activate();
}
Использование асинхронной активации предотвращает потерю фокуса и обеспечивает корректную работу с динамическими формами и списками.
Для интерфейсов с несколькими модальными окнами или всплывающими
панелями можно применять методы pause и
unpause:
const secondaryTrap = createFocusTrap(secondaryModal);
primaryTrap.pause();
secondaryTrap.activate();
// После закрытия вторичной панели
secondaryTrap.deactivate();
primaryTrap.unpause();
Это позволяет переключать фокус между несколькими контейнерами без нарушения правил доступности.
Focus-trap корректно обрабатывает:
<input>, <button>,
<select>, <textarea><a> с hreftabindex="0" или положительным
значениемВажно избегать установки tabindex="-1" на элементы,
которые должны быть доступны через Tab, иначе они будут исключены из
цикла фокуса.
Проверка корректной работы фокус-трапа включает:
Навигация с клавиатуры
Tab и Shift+Tab должны циклически
обходить все фокусируемые элементы.Обработка клавиши Escape
escapeDeactivates модальное окно
должно закрываться без потери фокуса.Клики вне контейнера
clickOutsideDeactivates, клик
вне модального окна должен деактивировать ловушку.Совместимость со скринридерами
Асинхронный контент
initialFocus для первого поля формы или
кнопки подтверждения.returnFocusOnDeactivate, чтобы пользователь не
терял контекст интерфейса.pause/unpause вместо одновременной активации нескольких
ловушек.Focus-trap обеспечивает строгое соблюдение правил доступности при работе с интерактивными элементами и модальными окнами, позволяя создавать интерфейсы, безопасные и удобные для пользователей с ограниченными возможностями.