Библиотека Tabbable предназначена для определения всех элементов на странице, которые могут быть достигнуты с помощью клавиши Tab. Она обеспечивает точный контроль над последовательностью фокусировки, что критично для доступности интерфейсов.
Tabbable анализирует DOM и выделяет фокусируемые
элементы, включая <a>,
<button>, <input>,
<select>, <textarea> и элементы с
атрибутом tabindex. При этом учитываются следующие
особенности:
disabled исключаются из списка.tabindex="-1" игнорируются, так как они не
должны участвовать в последовательности табуляции.display: none или visibility: hidden не
включаются.Методы библиотеки возвращают массив объектов DOM, что позволяет использовать их для визуализации или программной модификации порядка табуляции.
Для извлечения элементов используется функция:
import { tabbable } from 'tabbable';
const elements = tabbable(document.body);
console.log(elements);
Результат — массив всех элементов, доступных для табуляции в текущей области документа. Этот массив упорядочен так, как элементы будут получать фокус при нажатии Tab.
Каждый элемент, возвращаемый библиотекой, обладает рядом свойств, влияющих на порядок табуляции:
tabindex получают фокус раньше,
чем элементы с tabindex=0.Для наглядного отображения порядка табуляции удобно создавать
анимацию или нумерованный список, где каждому
tabbable-элементу присваивается индекс из массива
tabbable(). Пример:
const elements = tabbable(document.body);
elements.forEach((el, index) => {
const badge = document.createElement('span');
badge.textContent = index + 1;
badge.style.position = 'absolute';
badge.style.background = 'red';
badge.style.color = 'white';
badge.style.fontSize = '12px';
badge.style.padding = '2px 5px';
badge.style.borderRadius = '50%';
badge.style.top = `${el.offsetTop}px`;
badge.style.left = `${el.offsetLeft}px`;
document.body.appendChild(badge);
});
Этот подход позволяет визуально отследить порядок
фокусировки и выявить элементы с неожиданным
tabindex.
В случаях, когда на странице присутствуют вложенные компоненты, например модальные окна или динамические формы, Tabbable помогает:
Пример ограничения табуляции внутри контейнера:
const modal = document.querySelector('.modal');
const modalTabbable = tabbable(modal);
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
const focusedIndex = modalTabbable.indexOf(document.activeElement);
if (e.shiftKey && focusedIndex === 0) {
e.preventDefault();
modalTabbable[modalTabbable.length - 1].focus();
} else if (!e.shiftKey && focusedIndex === modalTabbable.length - 1) {
e.preventDefault();
modalTabbable[0].focus();
}
}
});
Tabbable автоматически не отслеживает изменения DOM. При добавлении
или удалении элементов требуется повторный вызов функции
tabbable() для актуализации списка. Для удобства
можно создать обёртку:
function updateTabbable(container) {
return tabbable(container);
}
const container = document.querySelector('#dynamic-form');
let currentTabbable = updateTabbable(container);
// После добавления нового элемента
currentTabbable = updateTabbable(container);
Использование Tabbable важно не только для визуализации, но и для проверки доступности интерфейсов:
tabindex > 0, которые могут
нарушать естественный поток фокуса.tabindex,
отдавая предпочтение естественной последовательности DOM.Эти практики позволяют добиться интуитивной навигации с клавиатуры и соответствия стандартам доступности WCAG, обеспечивая корректное взаимодействие пользователей с любыми интерфейсами.