Библиотека Tabbable в JavaScript предназначена для
поиска и управления элементами интерфейса, доступными для навигации с
клавиатуры через клавишу Tab. Она используется для
обеспечения доступности (accessibility) и управления
фокусом в кастомных компонентах.
Основной принцип работы библиотеки заключается в том, что она
проверяет элементы на соответствие условиям фокусируемости: видимость,
наличие атрибута tabindex, свойства disabled,
hidden и CSS-свойств, влияющих на отображение.
Установка производится через npm:
npm install tabbable
Подключение в проекте:
import { tabbable, isTabbable } from 'tabbable';
tabbable(container) — возвращает массив всех элементов
внутри container, доступных для табуляции.isTabbable(element) — возвращает true,
если элемент может быть сфокусирован через Tab.Для кастомных компонентов важно правильно определить элементы,
которые должны участвовать в табуляции. tabbable()
выполняет комплексную проверку:
Видимость элемента: элемент не должен быть скрыт
через display: none или
visibility: hidden.
Атрибуты управления фокусом:
tabindex="-1" делает элемент доступным для программного
фокуса, но исключает из таб-цикла.tabindex="0" добавляет элемент в стандартный
таб-цикл.tabindex позволяют задавать порядок
фокуса вручную.Отключенные элементы: disabled
исключает элемент из табуляции.
Пример использования:
const container = document.getElementById('modal');
const focusableElements = tabbable(container);
console.log(focusableElements); // массив всех tabbable элементов внутри модалки
Для кастомных элементов, таких как выпадающие списки, модальные окна или панели аккордеонов, необходимо вручную управлять табуляцией, так как стандартные HTML-элементы не всегда используются.
Кастомный селект может быть реализован с элементами div
и span вместо <select> и
<option>. Для корректной табуляции:
Каждому интерактивному элементу назначается
tabindex="0".
Для закрытого состояния меню фокус может быть ограничен:
При открытии списка вызывается tabbable() для поиска
всех опций и управление фокусом через клавиши
ArrowUp/ArrowDown.
const optionsContainer = document.querySelector('.custom-select-options');
function getFocusableOptions() {
return tabbable(optionsContainer);
}
document.addEventListener('keydown', (event) => {
if (event.key === 'ArrowDown') {
const focusables = getFocusableOptions();
focusables[0].focus();
}
});
Для модального окна важно захватывать фокус внутри контейнера. Это предотвращает уход фокуса на элементы под модалкой. Пример паттерна «фокус-ловушка»:
const modal = document.querySelector('#modal');
const focusableEls = tabbable(modal);
const firstEl = focusableEls[0];
const lastEl = focusableEls[focusableEls.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstEl) {
e.preventDefault();
lastEl.focus();
} else if (!e.shiftKey && document.activeElement === lastEl) {
e.preventDefault();
firstEl.focus();
}
}
});
Библиотека автоматически проверяет текущее состояние DOM. Если
элементы появляются или исчезают динамически,
tabbable(container) всегда возвращает актуальный список.
Это особенно важно для компонентов, где элементы добавляются через
JavaScript после инициализации.
В React, Vue или Angular компоненты часто генерируют элементы динамически. Для корректной табуляции:
ref для доступа к DOM-узлам
контейнера.tabbable(ref.current) после рендера
компонента.Пример в React:
import { useEffect, useRef } from 'react';
import { tabbable } from 'tabbable';
function Modal({ isOpen }) {
const modalRef = useRef();
useEffect(() => {
if (isOpen && modalRef.current) {
const focusables = tabbable(modalRef.current);
focusables[0]?.focus();
}
}, [isOpen]);
return (
<div ref={modalRef} className="modal">
<button>Закрыть</button>
<input type="text" />
<button>Подтвердить</button>
</div>
);
}
tabindex и событий клавиатуры.tabbable() для поиска фокусируемых
элементов.tabindex для кастомных компонентов.Эта последовательность позволяет создать доступные, управляемые и предсказуемые интерфейсы, соответствующие стандартам WCAG и UX-практикам для клавиатурной навигации.