Библиотека Focus Trap предназначена для управления фокусом клавиатуры внутри определённого DOM‑контейнера. Основная задача — ограничить перемещение фокуса элементами внутри выбранной области. Такая логика применяется в модальных окнах, всплывающих диалогах, выпадающих панелях, полноэкранных меню и других интерфейсных элементах, временно блокирующих взаимодействие с остальной частью страницы.
Параметр escapeDeactivates управляет поведением ловушки
фокуса при нажатии клавиши Escape. Он определяет,
должна ли ловушка автоматически деактивироваться, когда пользователь
нажимает эту клавишу.
По умолчанию параметр включён. Это означает, что нажатие Escape завершает работу ловушки фокуса и возвращает управление странице.
Стандартная конфигурация Focus Trap предполагает, что клавиша Escape закрывает активную область взаимодействия. Такое поведение соответствует общепринятым принципам доступности интерфейсов.
Пример создания ловушки фокуса:
import { createFocusTrap } from 'focus-trap';
const trap = createFocusTrap('#modal');
trap.activate();
При такой конфигурации:
#modalПосле деактивации:
Параметр escapeDeactivates передаётся в объекте
конфигурации при создании ловушки.
const trap = createFocusTrap('#modal', {
escapeDeactivates: true
});
Значение true означает, что нажатие
Escape завершает работу ловушки.
Внутренний обработчик клавиатуры перехватывает событие
keydown, отслеживает код клавиши и инициирует деактивацию
ловушки.
В некоторых интерфейсах клавиша Escape не должна закрывать активную область. Например:
В таких случаях параметр можно отключить:
const trap = createFocusTrap('#modal', {
escapeDeactivates: false
});
Теперь нажатие Escape не приведёт к деактивации ловушки фокуса.
Фокус останется внутри контейнера, пока ловушка не будет отключена программно.
Пример ручного закрытия:
closeButton.addEventListener('click', () => {
trap.deactivate();
});
Параметр escapeDeactivates поддерживает не только булевы
значения, но и функцию. Это позволяет динамически решать, следует ли
деактивировать ловушку.
Сигнатура функции:
escapeDeactivates: (event) => boolean
Функция получает объект события KeyboardEvent.
Пример:
const trap = createFocusTrap('#modal', {
escapeDeactivates: (event) => {
return !event.altKey;
}
});
В этом случае:
Такой механизм позволяет реализовывать более сложные сценарии управления интерфейсом.
Иногда закрытие модального окна зависит от состояния интерфейса. Например, форма может содержать несохранённые изменения.
let hasUnsavedChanges = true;
const trap = createFocusTrap('#modal', {
escapeDeactivates: () => {
return !hasUnsavedChanges;
}
});
Если переменная hasUnsavedChanges равна
true, нажатие Escape не закроет окно.
Focus Trap устанавливает собственный обработчик keydown.
Если escapeDeactivates включён, библиотека:
При использовании пользовательских обработчиков важно учитывать порядок выполнения.
Пример:
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
console.log('Escape pressed');
}
});
Если ловушка фокуса активна и escapeDeactivates равен
true, деактивация произойдёт до или одновременно с
пользовательскими обработчиками, в зависимости от порядка регистрации
событий.
onDeactivateЧасто параметр escapeDeactivates используется вместе с
колбэком onDeactivate.
const trap = createFocusTrap('#modal', {
escapeDeactivates: true,
onDeactivate: () => {
modal.classList.remove('active');
}
});
Последовательность событий:
onDeactivateЭто позволяет синхронизировать логику интерфейса с управлением фокусом.
Клавиша Escape является стандартным способом закрытия модальных окон и диалогов. Многие рекомендации по доступности интерфейсов, включая WCAG и ARIA‑практики, предполагают поддержку этой клавиши.
Поэтому отключение escapeDeactivates должно
использоваться только при обоснованной необходимости. Отсутствие реакции
на Escape может:
Если автоматическая деактивация отключена, необходимо предусмотреть альтернативный механизм выхода из ловушки.
import { createFocusTrap } from 'focus-trap';
const modal = document.querySelector('#modal');
const trap = createFocusTrap(modal, {
escapeDeactivates: true,
clickOutsideDeactivates: true,
onActivate: () => {
modal.classList.add('active');
},
onDeactivate: () => {
modal.classList.remove('active');
}
});
openButton.addEventListener('click', () => {
trap.activate();
});
Особенности поведения:
В сложных интерфейсах могут существовать вложенные ловушки фокуса. Например:
В таких случаях Escape обычно закрывает последнюю активную ловушку.
Пример:
При нажатии Escape:
Если у внутренней ловушки escapeDeactivates: false,
Escape будет передан внешней ловушке.
Некоторые компоненты могут перехватывать Escape раньше Focus Trap. Например:
В таких случаях обработчик может вызвать
event.stopPropagation(), и событие не достигнет ловушки
фокуса.
Это следует учитывать при проектировании архитектуры клавиатурных событий.
Отключение Escape без альтернативного выхода
escapeDeactivates: false
При отсутствии кнопки закрытия пользователь может оказаться заблокирован внутри ловушки.
Дублирование логики закрытия
Иногда разработчики одновременно используют
escapeDeactivates и собственный обработчик Escape:
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
trap.deactivate();
}
});
Это может привести к повторной деактивации и лишним вызовам обработчиков.
Использование сложной логики внутри функции
Функция escapeDeactivates должна выполнять только
проверку условия. Тяжёлые операции или асинхронная логика могут вызвать
задержки обработки клавиатуры.
Основные свойства escapeDeactivates:
boolean | functiontrueГибкость этого параметра позволяет точно контролировать поведение интерфейса при взаимодействии с клавиатурой, сохраняя при этом соответствие требованиям доступности и ожидаемым пользовательским сценариям.