Focus-trap — это библиотека на JavaScript, предназначенная для управления фокусом внутри ограниченной области DOM, обычно модальных окон, выпадающих меню, сайдбаров и других интерактивных компонентов. Основная задача — предотвратить уход фокуса за пределы заданного контейнера при использовании клавиатуры, что критично для доступности интерфейсов.
Библиотека предоставляет удобный API для создания «ловушек фокуса» и
их управления. Основной объект создаётся с помощью функции
createFocusTrap:
import { createFocusTrap } from 'focus-trap';
const modalTrap = createFocusTrap('#modal', {
onActivate: () => console.log('Trap activated'),
onDeactivate: () => console.log('Trap deactivated'),
escapeDeactivates: true,
clickOutsideDeactivates: false,
initialFocus: '#modal input:first-of-type'
});
Здесь ключевые параметры:
onActivate и
onDeactivate — коллбэки при активации и
деактивации ловушки.escapeDeactivates — разрешает закрытие
ловушки при нажатии Esc.clickOutsideDeactivates — позволяет
деактивировать ловушку при клике вне контейнера.initialFocus — задаёт элемент, который
получит фокус при активации.Focus-trap предоставляет несколько методов для динамического контроля:
activate() — активирует ловушку
фокуса.deactivate() — деактивирует ловушку и
возвращает фокус на элемент, который был активен до активации.pause() и
unpause() — временно приостанавливают
работу ловушки без её полной деактивации. Это полезно для вложенных
модальных окон.Пример использования:
modalTrap.activate();
// Внутри модального окна открылось другое меню
modalTrap.pause();
// Работа внутреннего меню с фокусом
modalTrap.unpause();
modalTrap.deactivate();
Focus-trap позволяет гибко контролировать:
allowOutsideClick — можно передать
функцию, которая проверяет, разрешён ли клик за пределами
контейнера.fallbackFocus — элемент, на который
фокус попадёт, если initialFocus не найден.tabbableOptions — объект с параметрами
для библиотеки tabbable, позволяющий исключить элементы из
обхода фокуса или изменить порядок навигации.Пример:
const trap = createFocusTrap('#menu', {
fallbackFocus: '#menu',
tabbableOptions: { displayCheck: 'none' }
});
Для переиспользуемых компонентов важно создавать ловушку фокуса один раз и управлять её активацией в зависимости от состояния UI. Это уменьшает дублирование кода и предотвращает ошибки при работе с несколькими модальными окнами.
Пример с динамическим модальным окном:
function openModal(modalId) {
const modal = document.getElementById(modalId);
const trap = createFocusTrap(modal, {
initialFocus: modal.querySelector('input') || modal
});
trap.activate();
modal.style.display = 'block';
modal.querySelector('.close').addEventListener('click', () => {
trap.deactivate();
modal.style.display = 'none';
});
}
В ситуациях, когда внутри модального окна открывается ещё один
интерактивный компонент (например, подсказка или дополнительное меню),
важно использовать pause и unpause для
родительской ловушки, чтобы не нарушать пользовательский поток:
parentTrap.activate();
childTrap.activate(); // вложенная ловушка
parentTrap.pause();
// После закрытия дочернего компонента
childTrap.deactivate();
parentTrap.unpause();
Focus-trap обеспечивает правильное поведение клавиш:
escapeDeactivates: true).Особое внимание уделяется элементам, которые могут быть скрыты или
временно недоступны. Опция tabbableOptions.displayCheck
позволяет исключать скрытые элементы из обхода фокуса, что предотвращает
неожиданное поведение при динамическом изменении DOM.
activate и
deactivate.initialFocus для улучшения
пользовательского опыта и доступности.pause и unpause для вложенных
интерактивных элементов.Focus-trap позволяет создавать полностью переиспользуемые, доступные и управляемые компоненты интерфейса, обеспечивая корректное поведение фокуса во всех сценариях взаимодействия.