Библиотека Focus-trap предназначена для создания управляемых зон фокуса в веб-приложениях. Основная цель — ограничение навигации с помощью клавиатуры (Tab/Shift+Tab) внутри заданного контейнера, что особенно важно для модальных окон, выпадающих меню и других интерактивных компонентов. Focus-trap позволяет избежать потери фокуса и неконтролируемой навигации по странице, обеспечивая предсказуемое взаимодействие.
Фокусировка в DOM определяется элементами с атрибутом
tabindex и интерактивными тегами (button,
input, select, a[href]).
Focus-trap оборачивает контейнер, контролируя все события клавиатуры,
чтобы фокус оставался внутри этого контейнера до явного выхода.
Для базовой инициализации достаточно импортировать библиотеку и
вызвать createFocusTrap:
import { createFocusTrap } from 'focus-trap';
const modal = document.getElementById('modal');
const focusTrap = createFocusTrap(modal, {
onActivate: () => modal.classList.add('is-active'),
onDeactivate: () => modal.classList.remove('is-active')
});
// Активация трапа
focusTrap.activate();
// Деактивация трапа
focusTrap.deactivate();
Ключевые моменты:
activate() фиксирует фокус внутри контейнера.deactivate() возвращает фокус на элемент,
активировавший трап, если опция returnFocusOnDeactivate
включена (по умолчанию true).onActivate и onDeactivate позволяют
интегрировать визуальные эффекты или другие действия при
активации/деактивации трапа.В сложных интерфейсах модальные окна и динамические компоненты часто создаются только при необходимости. Преждевременная инициализация Focus-trap может привести к ошибкам, так как контейнер может быть ещё не добавлен в DOM. Для этого применяется отложенная инициализация, когда создание трапа выполняется только после рендера элемента.
let focusTrap;
function openModal() {
const modal = document.createElement('div');
modal.id = 'modal';
modal.innerHTML = `
<button id="close">Закрыть</button>
<input placeholder="Имя" />
<button>Отправить</button>
`;
document.body.appendChild(modal);
focusTrap = createFocusTrap(modal, {
onActivate: () => modal.classList.add('is-active'),
onDeactivate: () => modal.remove()
});
focusTrap.activate();
}
Особенности отложенной инициализации:
Focus-trap предоставляет множество опций для гибкого управления:
escapeDeactivates — деактивация при
нажатии Esc (true по умолчанию).clickOutsideDeactivates — деактивация
при клике вне контейнера.initialFocus — элемент, который
получит фокус при активации трапа. Можно указать селектор или функцию,
возвращающую элемент.fallbackFocus — элемент, на который
фокус будет перемещён, если initialFocus не найден.focusTrap = createFocusTrap(modal, {
escapeDeactivates: true,
clickOutsideDeactivates: true,
initialFocus: '#modal input',
fallbackFocus: '#modal button'
});
В одностраничных приложениях (SPA) часто используется создание компонентов на лету. Отложенная инициализация Focus-trap обеспечивает:
Пример с динамическим компонентом:
document.getElementById('openModalBtn').addEventListener('click', () => {
openModal();
});
document.body.addEventListener('click', (event) => {
if(event.target.matches('#close')) {
focusTrap.deactivate();
}
});
returnFocusOnDeactivate для
автоматического возврата фокуса к элементу, открывшему модал.initialFocus и fallbackFocus, чтобы избежать
ошибок.Focus-trap легко интегрируется с фреймворками вроде React, Vue и Svelte. При этом важно учитывать жизненный цикл компонента: трап должен создаваться после монтирования элемента и уничтожаться при размонтировании. Это позволяет избежать попыток фокусировки на ещё не существующих DOM-узлах.
Такой подход к управлению фокусом обеспечивает удобство навигации и соблюдение стандартов доступности, одновременно поддерживая динамический, интерактивный интерфейс с множеством модальных элементов.