Обратная совместимость

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

Ключевые моменты работы:

  • Фокусируемость элементов: библиотека проверяет, может ли элемент получить фокус. Это включает интерактивные элементы (<button>, <input>, <a> с href), а также элементы с tabindex ≥ 0.
  • Видимость: элементы, скрытые через CSS (display: none, visibility: hidden) или вне видимой области, исключаются из списка.
  • Отслеживание атрибутов: disabled, aria-hidden, tabindex="-1" исключают элемент из навигации.

Методы и интерфейсы

tabbable(root, options)

Основной метод библиотеки возвращает массив фокусируемых элементов внутри указанного корня root.

Параметры:

  • root — DOM-элемент, внутри которого производится поиск.

  • options (необязательный объект):

    • includeContainer (boolean) — включать ли сам root в результат, если он фокусируем.
    • getShadowRoot (function) — кастомная функция для обхода Shadow DOM.
    • tabindex — позволяет переопределять стандартное поведение элементов с tabindex.

Пример структуры вызова:

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

isTabbable(element)

Проверяет, может ли отдельный элемент быть частью последовательности Tab.

  • Возвращает true, если элемент видим, интерактивен и не заблокирован.
  • Возвращает false для элементов с tabindex="-1" или скрытых элементов.

focusable(element)

Определяет, может ли элемент вообще получать фокус программно (element.focus()), независимо от его позиции в последовательности Tab. Отличие от isTabbable в том, что focusable не учитывает порядок табуляции.

Особенности обратной совместимости

Поддержка старых браузеров

Tabbable обеспечивает корректную работу в браузерах, начиная с IE11 и выше, благодаря:

  • Проверке свойств offsetParent, getClientRects().
  • Игнорированию нестандартных или устаревших атрибутов, влияющих на фокус.
  • Корректной работе с элементами fieldset, legend, которые в старых браузерах имели особое поведение.

Shadow DOM и iframe

Для обратной совместимости важно учитывать ограничения старых движков:

  • Shadow DOM в старых браузерах отсутствует, поэтому getShadowRoot по умолчанию возвращает null.
  • Элементы внутри <iframe> можно обходить только при наличии доступа к содержимому через contentDocument.

Атрибут tabindex

  • Значения tabindex ≤ -1 делают элемент недоступным для навигации, что сохраняется для старых браузеров.
  • Значения tabindex = 0 и положительные числа корректно учитываются в последовательности табуляции.
  • Библиотека учитывает нестандартные сценарии, когда tabindex динамически меняется через JS, поддерживая обратную совместимость с элементами, созданными до обновления DOM.

Особенности с CSS

  • Элементы с display: none или visibility: hidden игнорируются независимо от браузера.
  • Элементы, скрытые с помощью отрицательных координат или clip-path, могут быть обработаны по-разному в старых движках, поэтому библиотека использует универсальные методы getClientRects() и offsetWidth/offsetHeight.

Производительность и обход DOM

Tabbable оптимизирована для больших деревьев DOM:

  • Использует ленивый обход, избегая глубоких рекурсий для невидимых узлов.
  • Кэширует результаты проверки видимости и фокусируемости для элементов внутри Shadow DOM и iframe.
  • Поддерживает работу с динамически добавляемыми элементами через повторный вызов функции tabbable.

Использование в сложных интерфейсах

  • Модальные окна: можно быстро получить фокусируемые элементы для ограничения навигации внутри окна.
  • Динамически обновляемые списки и таблицы: библиотека позволяет корректно пересчитывать последовательность табуляции.
  • Кастомные виджеты: с tabindex и aria-атрибутами можно настроить поведение без потери совместимости с устаревшими браузерами.

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

  • Для сохранения обратной совместимости использовать стандартные интерактивные элементы там, где это возможно.

  • Проверять результаты tabbable() после динамических изменений DOM.

  • Для сложных компонентов с Shadow DOM использовать getShadowRoot для корректного обхода в современных браузерах, при этом старые браузеры будут игнорировать Shadow DOM без ошибок.

  • В сценариях с iframe убедиться, что доступ к contentDocument разрешен, иначе элементы внутри iframe не будут учитываться.

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