Библиотека Focus-trap предназначена для управления фокусом в пределах заданного DOM-элемента. Основная задача — гарантировать, что пользователи клавиатуры не смогут случайно выйти за пределы интерактивного контейнера, например, модального окна, всплывающей панели или меню.
Фокус в веб-приложении перемещается по элементам с помощью клавиши
Tab и Shift+Tab. Focus-trap создаёт «ловушку»,
перехватывая события навигации и возвращая фокус к первому или
последнему элементу при попытке выйти за пределы контейнера.
Для работы с Focus-trap требуется импорт библиотеки и создание
инстанса с помощью метода createFocusTrap. Стандартная
структура выглядит так:
import { createFocusTrap } from 'focus-trap';
const modal = document.getElementById('modal');
const trap = createFocusTrap(modal, {
escapeDeactivates: true,
clickOutsideDeactivates: true,
fallbackFocus: modal,
returnFocusOnDeactivate: true
});
Параметры конфигурации:
escapeDeactivates — закрытие ловушки при нажатии
Escape.clickOutsideDeactivates — деактивация при клике вне
контейнера.fallbackFocus — элемент, на который вернётся фокус,
если внутри нет доступных для фокуса элементов.returnFocusOnDeactivate — возврат фокуса к элементу,
который инициировал активацию ловушки.Ловушка фокуса активируется вызовом метода
trap.activate(). В этот момент Focus-trap запоминает
текущий активный элемент, чтобы вернуть на него фокус после деактивации.
Деактивация происходит с помощью trap.deactivate(). При
этом:
returnFocusOnDeactivate.const openButton = document.getElementById('openModal');
openButton.addEventListener('click', () => trap.activate());
const closeButton = document.getElementById('closeModal');
closeButton.addEventListener('click', () => trap.deactivate());
Ключевой аспект — корректное возвращение фокуса. Focus-trap обеспечивает консистентность пользовательского опыта:
setReturnFocus.const trap = createFocusTrap(modal, {
returnFocusOnDeactivate: false
});
// Сохранение триггера вручную
let triggerElement;
openButton.addEventListener('click', () => {
triggerElement = document.activeElement;
trap.activate();
});
// Возврат на триггер после закрытия
closeButton.addEventListener('click', () => {
trap.deactivate();
if (triggerElement) triggerElement.focus();
});
Focus-trap корректно работает с элементами, которые добавляются или
удаляются динамически. Для этого используется fallbackFocus
или обновление контейнера:
trap.updateContainer(modal);
Если внутри нет доступных интерактивных элементов, фокус перемещается
на fallbackFocus.
При наличии нескольких модальных окон или всплывающих элементов важно учитывать приоритет ловушек. Focus-trap поддерживает вложенные ловушки:
checkCanReturnFocus для
асинхронной проверки возможности возврата фокуса.const innerTrap = createFocusTrap(innerModal, {
returnFocusOnDeactivate: true
});
innerTrap.activate();
Для обеспечения доступности важно:
aria-hidden на элементах вне
активной ловушки.tabindex="0" или
tabindex="-1" для элементов, на которые требуется вернуть
фокус.fallbackFocus является интерактивным
элементом.Focus-trap предоставляет события:
onActivate — срабатывает при активации.onDeactivate — при деактивации.onPostActivate — после завершения активации.onPostDeactivate — после завершения деактивации.Это позволяет создавать пользовательские анимации и отслеживать жизненный цикл модального окна.
const trap = createFocusTrap(modal, {
onActivate: () => console.log('Trap activated'),
onDeactivate: () => console.log('Trap deactivated')
});
Эти события полезны для синхронизации состояния интерфейса и возвращения фокуса к нужному элементу.
returnFocusOnDeactivate: true для
стандартных модальных окон.fallbackFocus на безопасный интерактивный
элемент.Focus-trap обеспечивает корректное управление фокусом, повышая доступность и предсказуемость поведения клавиатурной навигации в веб-приложениях.