Библиотека Focus-trap предназначена для управления фокусом внутри заданного DOM-элемента, предотвращая выход фокуса за его пределы. Это критически важно для модальных окон, всплывающих меню, кастомных диалогов и других интерфейсных компонентов, где пользователь должен оставаться в пределах интерактивной области.
Focus-trap работает за счёт перехвата событий Tab и
Shift+Tab, а также программного управления фокусом,
обеспечивая циклическое перемещение между фокусируемыми элементами
внутри контейнера.
Ключевые понятия:
Escape.Focus-trap распространяется через npm:
npm install focus-trap
Подключение в проекте:
import { createFocusTrap } from 'focus-trap';
Создание простой ловушки для модального окна:
const modal = document.getElementById('modal');
const trap = createFocusTrap(modal, {
initialFocus: '#modal input:first-of-type',
escapeDeactivates: true,
clickOutsideDeactivates: true
});
// Активация ловушки
trap.activate();
Параметры конфигурации:
initialFocus — CSS-селектор или DOM-элемент, который
получит фокус при активации.escapeDeactivates — true/false, определяет
возможность выхода из ловушки клавишей Escape.clickOutsideDeactivates — true/false,
разрешает деактивацию при клике вне контейнера.returnFocusOnDeactivate — возвращает фокус к элементу,
который был активен до активации.Focus-trap отслеживает все элементы, способные получать фокус внутри
контейнера (tabindex, button,
input, a[href], select,
textarea, iframe).
Tab): если
текущий элемент последний в списке, фокус переносится на первый.Shift+Tab):
если текущий элемент первый, фокус переносится на последний.Можно вручную управлять фокусом:
trap.focusFirstElement(); // Фокус на первый элемент
trap.focusLastElement(); // Фокус на последний элемент
При изменении DOM внутри ловушки необходимо обновлять список
фокусируемых элементов. Focus-trap автоматически отслеживает
добавление/удаление элементов через MutationObserver.
Пример:
const trap = createFocusTrap('#modal', {
allowOutsideClick: true,
fallbackFocus: '#modal'
});
// Добавление динамического контента
const input = document.createElement('input');
modal.appendChild(input);
// После добавления нового элемента фокус корректно будет циклично перемещаться
Параметр fallbackFocus используется, если внутри
контейнера нет фокусируемых элементов — фокус будет установлен на
указанный элемент.
Для React часто используют ref для контейнера:
import { useRef, useEffect } from 'react';
import { createFocusTrap } from 'focus-trap';
function Modal({ isOpen }) {
const modalRef = useRef(null);
useEffect(() => {
const trap = createFocusTrap(modalRef.current, { escapeDeactivates: true });
if (isOpen) trap.activate();
return () => trap.deactivate();
}, [isOpen]);
return <div ref={modalRef} role="dialog">...</div>;
}
Важно корректно деактивировать ловушку при закрытии компонента, иначе фокус может “застрять” вне интерфейса.
Focus-trap поддерживает следующие расширенные сценарии:
tabindex или модифицировать
focusableElements при создании ловушки.Пример вложенной ловушки:
const parentTrap = createFocusTrap('#parent', { escapeDeactivates: false });
const childTrap = createFocusTrap('#child', { escapeDeactivates: true });
// При открытии дочернего окна
childTrap.activate();
// При закрытии — возвращение к родительской
childTrap.deactivate();
parentTrap.activate();
Focus-trap облегчает тестирование пользовательского взаимодействия:
const trap = createFocusTrap('#modal');
trap.activate();
const focusable = trap.getElements();
focusable[focusable.length - 1].focus();
simulateTab(); // пользователь нажал Tab
assert(document.activeElement === focusable[0]);
trap.activate();
simulateEscape();
assert(!trap.active); // ловушка деактивирована
const button = document.querySelector('#open-modal');
button.focus();
trap.activate();
trap.deactivate();
assert(document.activeElement === button);
Библиотека совместима с Cypress, Playwright и Puppeteer, позволяя
эмулировать нажатия клавиш Tab, Shift+Tab и
Escape.
Использование Focus-trap улучшает доступность:
dialog или
alertdialog помогает скринридерам.Правильная конфигурация обеспечивает соответствие стандартам WCAG 2.1 и ARIA.
Focus-trap — универсальный инструмент для контроля фокуса, особенно важный для комплексных интерфейсов, модальных окон, всплывающих форм и приложений с динамическим контентом. Он обеспечивает цикличность фокуса, безопасность навигации клавиатурой и простую интеграцию с E2E-тестами и современными фреймворками.