Функция tabbable

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


Основная концепция

Функция tabbable принимает DOM-элемент или контейнер и возвращает массив элементов, которые могут быть сфокусированы через клавишу Tab. Эти элементы называются таб-индексируемыми (tabbable). Ключевые критерии, которые определяют tabbable-элемент:

  1. Элемент должен быть видимым (display !== 'none' и visibility !== 'hidden').
  2. Элемент не должен быть отключён (disabled).
  3. Элемент должен быть интерактивным по природе: ссылки (<a> с href), кнопки (<button>), поля ввода (<input>, <textarea>), селекты (<select>), элементы с явным tabindex.

Синтаксис

import { tabbable } from 'tabbable';

const elements = tabbable(container);

Параметры:

  • container – DOM-элемент, внутри которого производится поиск tabbable-элементов. Если передан document.body, будет выполнен поиск по всей странице.

Возвращаемое значение:

  • Массив DOM-элементов, отсортированных в порядке естественной табуляции страницы.

Обработка tabindex

Элемент с атрибутом tabindex может влиять на порядок фокуса:

  • tabindex="0" – элемент включается в естественный порядок табуляции.
  • tabindex="-1" – элемент фокусируемый программно, но исключён из табуляции.
  • Положительные значения tabindex – элементы получают приоритет и располагаются перед элементами с tabindex="0".

Функция tabbable учитывает эти правила и возвращает элементы в правильном порядке. Элементы с tabindex="-1" в итоговый массив не включаются.


Фильтрация элементов

Библиотека автоматически исключает из результата элементы, которые:

  • скрыты через CSS (display: none или visibility: hidden);
  • имеют нулевой размер (offsetWidth и offsetHeight равны нулю);
  • являются disabled (для <button>, <input> и <select>);
  • не являются интерактивными и не имеют tabindex.

Дополнительно можно реализовать фильтры по кастомным условиям. Например, исключать элементы с определённым классом:

const elements = tabbable(container).filter(el => !el.classList.contains('no-tab'));

Особенности работы с модальными окнами

При использовании модальных окон важно ограничить табуляцию только внутренними элементами модального диалога. С помощью tabbable можно получить все фокусируемые элементы внутри модального контейнера:

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

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

modal.addEventListener('keydown', (event) => {
  if (event.key === 'Tab') {
    const first = focusableElements[0];
    const last = focusableElements[focusableElements.length - 1];
    
    if (event.shiftKey && document.activeElement === first) {
      last.focus();
      event.preventDefault();
    } else if (!event.shiftKey && document.activeElement === last) {
      first.focus();
      event.preventDefault();
    }
  }
});

Примеры использования

Получение всех фокусируемых элементов на странице:

import { tabbable } from 'tabbable';

const allTabbable = tabbable(document.body);
console.log(allTabbable);

Поиск tabbable-элементов внутри формы:

const form = document.querySelector('#loginForm');
const focusableFields = tabbable(form);

Комбинирование с кастомным фокусом:

const container = document.querySelector('.custom-section');
const elements = tabbable(container);

elements.forEach(el => {
  el.addEventListener('focus', () => {
    console.log('Фокус на элементе:', el);
  });
});

Важные нюансы

  • Элементы с отрицательным tabindex считаются фокусируемыми программно, но не включаются в стандартную табуляцию.
  • Скрытые элементы, даже если они интерактивные, игнорируются.
  • Порядок элементов в массиве соответствует естественной последовательности на странице, учитывая tabindex.

Практическая значимость

Использование функции tabbable позволяет:

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

Она часто применяется вместе с библиотеками для модальных окон, кастомных селекторов, тултипов и интерактивных компонентов.