Параметр escapeDeactivates

Библиотека Focus Trap предназначена для управления фокусом клавиатуры внутри определённого DOM‑контейнера. Основная задача — ограничить перемещение фокуса элементами внутри выбранной области. Такая логика применяется в модальных окнах, всплывающих диалогах, выпадающих панелях, полноэкранных меню и других интерфейсных элементах, временно блокирующих взаимодействие с остальной частью страницы.

Параметр escapeDeactivates управляет поведением ловушки фокуса при нажатии клавиши Escape. Он определяет, должна ли ловушка автоматически деактивироваться, когда пользователь нажимает эту клавишу.

По умолчанию параметр включён. Это означает, что нажатие Escape завершает работу ловушки фокуса и возвращает управление странице.


Поведение по умолчанию

Стандартная конфигурация Focus Trap предполагает, что клавиша Escape закрывает активную область взаимодействия. Такое поведение соответствует общепринятым принципам доступности интерфейсов.

Пример создания ловушки фокуса:

import { createFocusTrap } from 'focus-trap';

const trap = createFocusTrap('#modal');

trap.activate();

При такой конфигурации:

  • фокус остаётся внутри контейнера #modal
  • клавиша Tab переключает фокус только между элементами внутри модального окна
  • нажатие Escape автоматически деактивирует ловушку

После деактивации:

  • фокус возвращается к элементу, который был активен до открытия ловушки
  • пользователь снова может перемещаться по всей странице

Явное указание параметра

Параметр 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;
  }
});

В этом случае:

  • Escape без модификаторов закрывает ловушку
  • Escape вместе с Alt не деактивирует её

Такой механизм позволяет реализовывать более сложные сценарии управления интерфейсом.


Пример условной логики

Иногда закрытие модального окна зависит от состояния интерфейса. Например, форма может содержать несохранённые изменения.

let hasUnsavedChanges = true;

const trap = createFocusTrap('#modal', {
  escapeDeactivates: () => {
    return !hasUnsavedChanges;
  }
});

Если переменная hasUnsavedChanges равна true, нажатие Escape не закроет окно.


Взаимодействие с обработчиками клавиатуры

Focus Trap устанавливает собственный обработчик keydown. Если escapeDeactivates включён, библиотека:

  1. перехватывает событие клавиатуры
  2. проверяет, нажата ли клавиша Escape
  3. вызывает внутренний механизм деактивации

При использовании пользовательских обработчиков важно учитывать порядок выполнения.

Пример:

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');
  }
});

Последовательность событий:

  1. пользователь нажимает Escape
  2. ловушка деактивируется
  3. вызывается onDeactivate
  4. модальное окно скрывается

Это позволяет синхронизировать логику интерфейса с управлением фокусом.


Влияние на доступность интерфейса

Клавиша 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 обычно закрывает последнюю активную ловушку.

Пример:

  1. активируется ловушка модального окна
  2. внутри него открывается дополнительный диалог
  3. создаётся вторая ловушка

При нажатии Escape:

  • сначала деактивируется внутренняя ловушка
  • затем — внешняя

Если у внутренней ловушки escapeDeactivates: false, Escape будет передан внешней ловушке.


Особенности работы в сложных интерфейсах

Некоторые компоненты могут перехватывать Escape раньше Focus Trap. Например:

  • библиотеки управления горячими клавишами
  • редакторы кода
  • фреймворки UI

В таких случаях обработчик может вызвать event.stopPropagation(), и событие не достигнет ловушки фокуса.

Это следует учитывать при проектировании архитектуры клавиатурных событий.


Типичные ошибки использования

Отключение Escape без альтернативного выхода

escapeDeactivates: false

При отсутствии кнопки закрытия пользователь может оказаться заблокирован внутри ловушки.


Дублирование логики закрытия

Иногда разработчики одновременно используют escapeDeactivates и собственный обработчик Escape:

document.addEventListener('keydown', (event) => {
  if (event.key === 'Escape') {
    trap.deactivate();
  }
});

Это может привести к повторной деактивации и лишним вызовам обработчиков.


Использование сложной логики внутри функции

Функция escapeDeactivates должна выполнять только проверку условия. Тяжёлые операции или асинхронная логика могут вызвать задержки обработки клавиатуры.


Краткая характеристика параметра

Основные свойства escapeDeactivates:

  • тип: boolean | function
  • значение по умолчанию: true
  • назначение: управление деактивацией ловушки при нажатии Escape
  • область применения: модальные окна, диалоги, панели, интерфейсы с ограничением фокуса
  • поддерживает условную логику через пользовательскую функцию

Гибкость этого параметра позволяет точно контролировать поведение интерфейса при взаимодействии с клавиатурой, сохраняя при этом соответствие требованиям доступности и ожидаемым пользовательским сценариям.