Библиотека Tabbable предназначена для определения всех элементов на веб-странице, которые могут получить фокус с помощью клавиши Tab. Она используется для управления доступностью интерфейсов и создания корректной навигации по элементам формы, меню и интерактивным компонентам. Базовый принцип работы заключается в обходе DOM-дерева и фильтрации элементов на основе их видимости, атрибутов и нативной возможности принимать фокус.
По умолчанию Tabbable учитывает следующие критерии:
display: none или
visibility: hidden)disabled
атрибут)tabindex или
является нативно фокусируемым (<a href>,
<button>, <input> и т.п.)Однако для сложных интерфейсов этого набора фильтров может быть недостаточно. В таких случаях необходимо настраивать собственные фильтры.
Tabbable предоставляет возможность задавать кастомные функции
фильтрации через параметр filter. Это позволяет гибко
управлять тем, какие элементы считаются табулябельными.
import { tabbable } from 'tabbable';
const customFilter = (element) => {
// Игнорировать все кнопки с классом .ignore-tab
if (element.matches('.ignore-tab')) return false;
// Разрешить табуляцию для элементов с data-tab-allow
if (element.hasAttribute('data-tab-allow')) return true;
// Применить стандартные правила Tabbable
return true;
};
const elements = tabbable(document.body, { filter: customFilter });
console.log(elements);
Ключевые моменты:
true для элементов, которые допустимо включать,
и false для исключаемых.data-*).Для интерфейсов с модальными окнами иногда необходимо игнорировать все элементы вне активного окна:
const modal = document.querySelector('.modal.active');
const modalFilter = (element) => modal.contains(element);
const tabbableElements = tabbable(document.body, { filter: modalFilter });
Иногда нужно включать в табуляцию только элементы с определёнными ARIA-ролями:
const roleFilter = (element) => ['button', 'link', 'textbox'].includes(element.getAttribute('role'));
const tabbableElements = tabbable(document.body, { filter: roleFilter });
Можно использовать текущие состояния компонентов, например, включать только элементы, отмеченные как активные:
const activeOnlyFilter = (element) => element.classList.contains('is-active');
const tabbableElements = tabbable(document.body, { filter: activeOnlyFilter });
Для более гибкой настройки удобно комбинировать фильтры через композицию:
const combineFilters = (...filters) => (element) =>
filters.every((filter) => filter(element));
const combinedFilter = combineFilters(
(el) => !el.disabled,
(el) => el.offsetParent !== null,
(el) => el.getAttribute('data-tab-allow') !== 'false'
);
const elements = tabbable(document.body, { filter: combinedFilter });
В этом примере элемент должен пройти все проверки:
не быть отключённым, быть видимым и иметь разрешение на табуляцию через
data-tab-allow.
data-*
позволяет легко управлять включением и исключением элементов без
изменения классов и структуры DOM.Настройка собственных фильтров в Tabbable делает управление фокусом гибким и безопасным. Грамотно спроектированные фильтры позволяют создавать доступные и предсказуемые интерфейсы даже в сложных SPA или компонентных библиотеках.