Анимация и фокус

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

Ключевые возможности:

  • Автоматический перевод фокуса на первый доступный интерактивный элемент внутри контейнера.
  • Перехват клавиши Tab и циклическая навигация по интерактивным элементам.
  • Опциональное возврат фокуса к элементу, с которого было активировано «ловушка фокуса», после её деактивации.

Установка и базовое использование

Установка через npm:

npm install focus-trap

Импорт и инициализация:

import { createFocusTrap } from 'focus-trap';

const modal = document.getElementById('modal');

const focusTrap = createFocusTrap(modal, {
  onActivate: () => modal.classList.add('is-active'),
  onDeactivate: () => modal.classList.remove('is-active'),
  clickOutsideDeactivates: true,
  escapeDeactivates: true
});

Объяснение параметров:

  • onActivate — функция, вызываемая при активации ловушки фокуса.
  • onDeactivate — функция при деактивации.
  • clickOutsideDeactivates — возможность закрытия ловушки кликом вне контейнера.
  • escapeDeactivates — закрытие по клавише Esc.

Активация и деактивация:

document.getElementById('openModal').addEventListener('click', () => focusTrap.activate());
document.getElementById('closeModal').addEventListener('click', () => focusTrap.deactivate());

Управление фокусом при анимации

При использовании анимации важно учитывать задержку появления элементов. Если активировать ловушку до завершения анимации, фокус может оказаться на невидимом элементе. Для синхронизации с CSS-анимацией применяются события transitionend или animationend.

Пример:

modal.addEventListener('transitionend', () => focusTrap.activate());
modal.classList.add('is-active');

Такой подход гарантирует, что фокус перейдёт только после того, как модальное окно визуально отобразится.

Настройка начального фокуса

По умолчанию фокус устанавливается на первый интерактивный элемент внутри контейнера. Можно указать конкретный элемент:

const focusTrap = createFocusTrap(modal, {
  initialFocus: '#modalInput'
});

initialFocus может быть:

  • CSS-селектором
  • DOM-элементом
  • Функцией, возвращающей элемент

Поддержка динамически создаваемых элементов

Если в контейнере появляются новые интерактивные элементы после активации ловушки фокуса, Focus-trap автоматически включает их в цикл навигации. Однако иногда требуется ручная синхронизация:

focusTrap.updateTabbableNodes();

Этот метод пересчитывает доступные для фокуса элементы и поддерживает корректную циклическую навигацию.

Управление фокусом при сложной анимации

Для более сложных случаев, когда элементы появляются поэтапно, можно использовать опцию checkCanFocusTrap:

const focusTrap = createFocusTrap(modal, {
  checkCanFocusTrap: (container) => {
    return new Promise((resolve) => {
      setTimeout(() => resolve(true), 300); // задержка для завершения анимации
    });
  }
});

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

Примеры интеграции с CSS-анимацией

Появление модального окна с плавной прозрачностью:

.modal {
  opacity: 0;
  transform: translateY(-20px);
  transition: opacity 0.3s, transform 0.3s;
}

.modal.is-active {
  opacity: 1;
  transform: translateY(0);
}
openButton.addEventListener('click', () => {
  modal.classList.add('is-active');
  modal.addEventListener('transitionend', () => focusTrap.activate(), { once: true });
});

Закрытие с анимацией:

closeButton.addEventListener('click', () => {
  modal.classList.remove('is-active');
  modal.addEventListener('transitionend', () => focusTrap.deactivate(), { once: true });
});

Рекомендации по доступности

  • Всегда возвращать фокус на инициирующий элемент после закрытия модального окна.
  • Использовать aria-hidden и inert для элементов вне модального окна, чтобы предотвратить их взаимодействие.
  • Проверять работу клавиши Tab и Shift+Tab при всех состояниях анимации.

Сочетание с другими библиотеками

Focus-trap легко интегрируется с фреймворками типа React, Vue или Angular через обёртки или хук-решения. В React, например, создаются эффекты, синхронизирующие активацию ловушки с состоянием компонента и CSS-анимациями.


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