Библиотека Focus-trap предназначена для управления
фокусом внутри конкретного DOM-элемента, предотвращая возможность
случайного выхода за пределы этого контейнера с помощью клавиши
Tab или Shift+Tab. Она особенно полезна для
модальных окон, выпадающих списков и других интерактивных элементов
интерфейса, где важно удерживать фокус внутри определённой зоны.
Фокусировка реализуется через создание trap instance, который контролирует активные элементы и слушает события клавиатуры. Основные методы:
activate() — включает ловушку фокуса, активируя
обработку клавиш.deactivate() — отключает ловушку, возвращая фокус к
исходному элементу.pause() и unpause() — временно
приостанавливают работу ловушки, что полезно при динамических изменениях
DOM.Примеры базовой инициализации:
import { createFocusTrap } from 'focus-trap';
const modal = document.querySelector('#modal');
const focusTrap = createFocusTrap(modal, {
escapeDeactivates: true,
clickOutsideDeactivates: true,
initialFocus: '#modal input:first-child',
});
focusTrap.activate();
При интеграции Focus-trap в сложные веб-приложения
часто возникают ситуации, когда другие библиотеки или собственный код
управления фокусом создают конфликты, приводящие к
неожиданным результатам: фокус «прыгает», клавиши Tab
перестают работать, или модальные окна закрываются некорректно.
UI-фреймворки с собственным управлением фокуса
Фреймворки вроде React Modal, Bootstrap Modal
или Material UI Dialog уже имеют встроенные механизмы
контроля фокуса. Если одновременно использовать Focus-trap, возможно
двойное срабатывание событий keydown или
focusin, что приводит к циклическому перемещению
фокуса.
Сторонние обработчики клавиатуры Любые
глобальные обработчики keydown или focus могут
перехватывать события, на которые полагается Focus-trap. Например, если
библиотека пытается отслеживать Tab для кастомной
навигации, фокус ловушки перестанет корректно перемещаться.
Динамическое изменение DOM Добавление или удаление интерактивных элементов в контейнере ловушки во время её работы может нарушить внутренний список фокусируемых элементов. Это особенно критично для реактивных фреймворков: React, Vue или Svelte.
pause и
unpause: при обновлении DOM внутри модального окна
рекомендуется временно приостановить ловушку, а затем возобновить.fallbackFocus и
initialFocus: эти опции предотвращают потерю
фокуса, когда элементы динамически меняются или удаляются.Пример безопасной работы с динамическим контентом:
focusTrap.pause();
updateModalContent(); // добавление или удаление элементов
focusTrap.unpause();
Конфликты с библиотеками управления анимацией
Анимационные библиотеки (например, GSAP или
Framer Motion) иногда скрывают или заменяют элементы через
display: none или opacity: 0. Focus-trap
игнорирует невидимые элементы, что может приводить к отсутствию
элементов для фокусировки. В таких случаях рекомендуется активировать
ловушку только после завершения анимации.
Управление глобальными событиями Для
совместимости с другими скриптами полезно подписываться на события через
focusin и focusout в рамках контейнера, а не
на весь документ. Это уменьшает вероятность перехвата фокуса другими
библиотеками.
Одновременное использование нескольких ловушек
Если приложение содержит несколько модальных окон, активных
одновременно, необходимо управлять порядком активации/деактивации
ловушек. Последовательно активируемая ловушка блокирует предыдущую:
focusTrap1.deactivate(); focusTrap2.activate();.
Тестирование с клавиатурой и скринридерами Проверка Tab-циклов, Escape, Shift+Tab и взаимодействия с ассистивными технологиями выявляет скрытые конфликты.
Логирование фокуса Для отладки удобно выводить текущий активный элемент:
document.addEventListener('focusin', (e) => {
console.log('Focused element:', e.target);
});
Это помогает выявить ситуации, когда фокус уходит за пределы ловушки.
Использование Focus-trap в сочетании с другими библиотеками требует
внимательного контроля порядка активации, состояния DOM и глобальных
обработчиков событий. Применение методов pause,
unpause, activate и deactivate, а
также точная настройка параметров initialFocus и
fallbackFocus позволяют минимизировать конфликты и
сохранять корректное управление фокусом в сложных интерфейсах.