Библиотека Focus-trap предназначена для управления фокусом внутри определённой области DOM, чаще всего модальных окон, всплывающих панелей или диалогов. Она гарантирует, что пользовательский фокус не покидает контейнер до явного выхода, предотвращая случайное взаимодействие с элементами вне области. Основная цель — обеспечить доступность интерфейса, соответствующую стандартам WAI-ARIA.
Фокусировка управляется через трап (trap), который
перехватывает нажатия клавиш, переход по табуляции (Tab и
Shift+Tab) и программно управляет элементами DOM.
Библиотека предоставляет методы для активации и
деактивации трапа, а также настраиваемые события при
выходе из зоны фокуса.
Трап создается с помощью функции createFocusTrap, куда
передается контейнер и набор опций:
import { createFocusTrap } from 'focus-trap';
const modal = document.getElementById('modal');
const focusTrap = createFocusTrap(modal, {
escapeDeactivates: true,
clickOutsideDeactivates: false,
initialFocus: '#modal input',
});
focusTrap.activate();
Ключевые моменты опций:
escapeDeactivates: при значении true
клавиша Escape снимает фокус с контейнера.clickOutsideDeactivates: контролирует возможность
деактивации при клике вне зоны.initialFocus: задает элемент, который получит фокус при
активации трапа.Сценарии, когда необходимо заблокировать возможность выхода из модального окна, реализуются через комбинацию опций:
const focusTrap = createFocusTrap(modal, {
escapeDeactivates: false,
clickOutsideDeactivates: false,
});
В этом случае ни клавиша Escape, ни клики за пределами
модального окна не приведут к деактивации трапа. Фокус остаётся строго
внутри контейнера до явного вызова метода deactivate().
Особенности поведения:
Tab или мышь вне модального окна.blur или потеря фокуса,
автоматически возвращают фокус внутрь контейнера.returnFocusOnDeactivate: true фокус
вернется к элементу, который был активен перед активацией трапа, но
только после явного вызова deactivate().Для сложных интерфейсов возможно динамически управлять деактивацией:
const focusTrap = createFocusTrap(modal, {
escapeDeactivates: false,
clickOutsideDeactivates: false,
onDeactivate: () => console.log('Попытка деактивации'),
});
focusTrap.activate();
// Программно попытка деактивации
focusTrap.deactivate({ returnFocus: false });
Даже при вызове deactivate() можно контролировать
возврат фокуса через параметр returnFocus. В ситуациях, где
необходима абсолютная блокировка, вызовы деактивации
можно перехватывать и отменять через пользовательские колбэки.
Focus-trap корректно работает с элементами, которые добавляются в DOM после активации:
const dynamicInput = document.createElement('input');
dynamicInput.id = 'dynamic';
modal.appendChild(dynamicInput);
При этом новая область автоматически включается в цикл фокусировки, если она находится внутри контейнера. Это позволяет создавать динамические формы, где блокировка выхода сохраняется на всех элементах.
В интерфейсах с несколькими модальными окнами важно соблюдать стек трапов. Например, если одно окно открыто над другим:
const trap1 = createFocusTrap(modal1);
const trap2 = createFocusTrap(modal2);
trap1.activate();
trap2.activate(); // Временно блокирует trap1
При закрытии верхнего трапа фокус возвращается в предыдущий. Если
верхний трап настроен с escapeDeactivates: false, выход
невозможен до явного вызова deactivate().
escapeDeactivates: false и
clickOutsideDeactivates: false для полного
контроля.onDeactivate для
логирования или отмены случайных деактиваций.returnFocusOnDeactivate или вручную через
document.activeElement.blur для предотвращения выхода — библиотека сама корректно
обрабатывает фокус.Эта архитектура делает Focus-trap надёжным инструментом для создания интерфейсов, где невозможность деактивации является требованием безопасности, UX или строгой последовательности действий пользователя.