Библиотека Focus-trap предназначена для управления фокусом в веб-приложениях. Основная задача — ограничить навигацию по элементам интерфейса определённой областью, например, модальными окнами, всплывающими меню или диалогами подтверждения. Она предотвращает выход фокуса за пределы контейнера, что улучшает доступность и предотвращает случайные действия пользователем.
Focus-trap работает как с обычными элементами DOM, так и с динамически создаваемыми, обеспечивая контролируемый цикл фокуса. При активации создаётся внутренняя структура для отслеживания всех фокусируемых элементов и установки правильного порядка перехода.
Создание фокуса начинается с вызова функции
createFocusTrap:
import { createFocusTrap } from 'focus-trap';
const modal = document.getElementById('modal');
const focusTrap = createFocusTrap(modal, {
escapeDeactivates: true,
clickOutsideDeactivates: true,
initialFocus: '#modal input:first-child'
});
Параметры конфигурации:
Активация производится методом activate():
focusTrap.activate();
Деактивация и очистка ресурсов выполняется через
deactivate():
focusTrap.deactivate();
Deactivation в Focus-trap не только возвращает фокус на предыдущий элемент, но и освобождает внутренние слушатели событий, предотвращая утечки памяти. Важно понимать, что каждый экземпляр ловушки создаёт несколько обработчиков:
keydown для отслеживания Tab и Shift+Tab.focusin для удержания фокуса внутри контейнера.click для контроля кликов вне контейнера.Если экземпляры не деактивируются, эти обработчики остаются активными, что может привести к накоплению обработчиков и снижению производительности.
Стандартная деактивация Метод
deactivate() снимает все внутренние обработчики и
восстанавливает исходный фокус. Этот способ подходит для большинства
случаев.
Динамическое уничтожение Если контейнер
удаляется из DOM до деактивации ловушки, необходимо вызвать
deactivate({ returnFocus: false }) для предотвращения
ошибок. Это гарантирует, что обработчики будут удалены, даже если фокус
невозможно вернуть.
Обработка нескольких ловушек Для сложных интерфейсов с несколькими модальными окнами или вкладками рекомендуется отключать предыдущую ловушку перед активацией новой:
if (activeTrap) {
activeTrap.deactivate();
}
activeTrap = createFocusTrap(newModal).activate();
MutationObserver для наблюдения за удалением
контейнера. В момент удаления вызывается deactivate, что
предотвращает оставшиеся слушатели.Focus-trap интенсивно использует события focusin и
keydown. Для больших приложений с множеством динамических
элементов важно:
fallbackFocus для обработки случаев,
когда нет фокусируемых элементов, чтобы избежать лишних циклов
проверки.const focusTrap = createFocusTrap(modal, {
fallbackFocus: modal
});
parentTrap.deactivate();
childTrap.activate();
childTrap.deactivate();
parentTrap.activate();
Анимации и задержки Если модальное окно
появляется с анимацией, активацию ловушки можно отложить с помощью
setTimeout или события окончания анимации, чтобы избежать
конфликта с первоначальной загрузкой DOM.
Интеграция с React или Vue В реактивных
фреймворках важно вызывать deactivate() в момент
размонтирования компонента (componentWillUnmount или
onBeforeUnmount) для предотвращения утечек памяти.
createFocusTrap должен иметь одного
владельца, отвечающего за активацию и деактивацию.deactivate.focusTrap.active
помогает контролировать текущее состояние и предотвращает множественные
активные экземпляры.onActivate и
onDeactivate позволяет выполнять дополнительные действия
при управлении ресурсами.const trap = createFocusTrap(modal, {
onActivate: () => console.log('Ловушка активирована'),
onDeactivate: () => console.log('Ловушка деактивирована')
});
Эффективная очистка ресурсов и контроль за активными ловушками повышают производительность приложения, предотвращают утечки памяти и обеспечивают корректное поведение интерфейса при динамическом изменении DOM.