Вложенные контейнеры

Библиотека Tabbable предназначена для управления фокусируемыми элементами на веб-странице, обеспечивая точное определение элементов, которые можно достигнуть с помощью клавиши Tab. В контексте вложенных контейнеров это особенно важно, поскольку структура DOM может включать несколько уровней вложенности, и необходимо корректно обрабатывать фокус внутри таких структур.

Определение контейнера и фокусируемых элементов

Любой DOM-элемент может выступать в роли контейнера для фокусируемых элементов. Фокусируемыми считаются:

  • <input> и <textarea>
  • <button> и <select>
  • Элементы с tabindex="0" или положительным значением
  • Элементы с contenteditable="true"

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

  1. Получить все фокусируемые элементы внутри контейнера.
  2. Игнорировать элементы вне заданного контейнера, даже если они доступны на странице.

Получение фокусируемых элементов во вложенном контейнере

Метод tabbable(container) возвращает массив элементов, доступных для табуляции внутри переданного контейнера:

import tabbable from 'tabbable';

const container = document.getElementById('parent');
const focusableElements = tabbable(container);

console.log(focusableElements);

При этом, если в контейнере присутствуют вложенные элементы с собственными интерактивными блоками, Tabbable корректно их обрабатывает. Элементы с атрибутом tabindex="-1" исключаются, что позволяет создавать области, недоступные для табуляции.

Контроль порядка табуляции

Вложенные контейнеры могут содержать элементы с явно заданным порядком через tabindex. Библиотека учитывает:

  • Положительные значения tabindex — элементы с меньшим числом получают приоритет.
  • Значение 0 — стандартный порядок в DOM.
  • Отрицательное значение -1 — элемент исключается из последовательности табуляции.

Пример управления порядком:

<div id="outer">
  <input type="text" tabindex="2">
  <div id="inner">
    <button tabindex="1">Внутренняя кнопка</button>
    <input type="text">
  </div>
  <button>Кнопка внешняя</button>
</div>
const outerContainer = document.getElementById('outer');
const elements = tabbable(outerContainer);

elements.forEach(el => console.log(el.tagName, el.tabIndex));

В результате библиотека вернёт элементы в порядке: кнопка внутри inner (tabindex=1), текстовое поле внешнего блока (tabindex=2), остальные элементы с tabindex=0 в DOM-последовательности.

Вложенные модальные окна и динамические контейнеры

Особенно важна работа с динамически создаваемыми или модальными контейнерами:

  • Для модальных окон можно использовать tabbable внутри модального контейнера, чтобы ограничить фокус только элементами модалки.
  • Вложенные модальные элементы (например, всплывающие подсказки или выпадающие меню) не нарушают последовательность табуляции внешнего контейнера, если использовать tabbable на нужном уровне.

Пример для модального окна:

const modal = document.querySelector('.modal');
const modalElements = tabbable(modal);

// Фокус на первый элемент
modalElements[0].focus();

Игнорирование неактивных контейнеров

В сложных интерфейсах с несколькими вкладками или панелями часто требуется исключить фокус для скрытых контейнеров. Tabbable позволяет фильтровать элементы с использованием CSS-свойств display: none или visibility: hidden. Вложенные элементы таких контейнеров автоматически исключаются:

const allFocusable = tabbable(document.body, { includeContainer: false });

Опция includeContainer позволяет включить сам контейнер в список, если он фокусируемый, что полезно для интерактивных панелей.

Работа с вложенными iframe

Вложенные контейнеры могут включать iframe. Tabbable может работать с элементами внутри iframe, если доступ к документу iframe разрешён через тот же источник. Для этого используется:

const iframeDocument = document.querySelector('iframe').contentDocument;
const iframeFocusable = tabbable(iframeDocument.body);

Таким образом, элементы внутри iframe обрабатываются как отдельный контейнер без влияния на внешние фокусируемые элементы.

Практические рекомендации

  • Всегда передавать конкретный контейнер для вложенных структур, чтобы избежать включения элементов за пределами интересующей области.
  • Использовать tabindex осознанно, особенно в сложных вложенных интерфейсах, чтобы управлять естественным порядком табуляции.
  • Для модальных окон и всплывающих панелей применять tabbable локально и управлять фокусом программно, чтобы исключить уход фокуса наружу.

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