Библиотека Tabbable предназначена для определения
элементов на странице, доступных для фокусировки с помощью клавиши
Tab. Она позволяет точно определить, какие элементы могут
быть интерактивными, а какие — игнорируются браузером при навигации по
клавиатуре. Библиотека полезна для улучшения доступности интерфейсов и
создания управляемых схем фокусировки.
Основной функционал реализован через функцию tabbable(),
которая принимает DOM-элемент или его контейнер и возвращает массив
элементов, доступных для фокусировки.
import { tabbable } from 'tabbable';
const focusableElements = tabbable(document.body);
console.log(focusableElements);
Возвращаемый массив упорядочен в том порядке, в котором элементы будут доступны при навигации с клавиатуры.
Для интерфейсов, где требуется реализовать быстрый поиск элементов по первой букве (например, в списках ссылок или меню), библиотека Tabbable служит базой для фильтрации элементов, доступных для фокусировки.
Сначала необходимо получить все фокусируемые элементы в контейнере:
const container = document.querySelector('#menu');
const focusableElements = tabbable(container);
На этом этапе focusableElements содержит только те
элементы, которые реально могут принимать фокус, исключая скрытые или
отключённые элементы.
Чтобы реализовать фильтр по первой букве, используется метод
filter() массива:
function filterByFirstLetter(elements, letter) {
const lowerLetter = letter.toLowerCase();
return elements.filter(el => {
const text = el.textContent.trim().toLowerCase();
return text.startsWith(lowerLetter);
});
}
const filteredElements = filterByFirstLetter(focusableElements, 'a');
Особенности работы:
toLowerCase() для обеспечения
нечувствительности к регистру.<a>,
<button>, <input> с типом
text, так и для других tabbable-элементов.Если DOM изменяется динамически (добавляются новые элементы или изменяется текст), необходимо обновлять массив tabbable-элементов перед фильтрацией:
function updateFilteredElements(container, letter) {
const elements = tabbable(container);
return filterByFirstLetter(elements, letter);
}
Такой подход гарантирует актуальность результатов поиска и корректную навигацию с клавиатуры.
После фильтрации часто требуется реализовать циклическую навигацию между найденными элементами:
let currentIndex = 0;
function focusNext(elements) {
if (elements.length === 0) return;
currentIndex = (currentIndex + 1) % elements.length;
elements[currentIndex].focus();
}
function focusPrevious(elements) {
if (elements.length === 0) return;
currentIndex = (currentIndex - 1 + elements.length) % elements.length;
elements[currentIndex].focus();
}
Эта схема позволяет переключаться между элементами по одной букве с
помощью собственных обработчиков клавиш, например, при перехвате события
keydown.
Tabbable учитывает следующие атрибуты при формировании списка элементов:
tabindex (значение -1 исключает элемент из
навигации, 0 или положительное число добавляет);disabled на <button>,
<input>, <select>,
<textarea>;display: none,
visibility: hidden, родитель с
display: none).При фильтрации по первой букве необходимо учитывать, что скрытые или отключенные элементы автоматически исключаются, что упрощает реализацию доступного поиска.
Можно комбинировать фильтр по первой букве с дополнительными условиями, например, по типу элемента:
function filterByLetterAndType(elements, letter, tagName) {
const lowerLetter = letter.toLowerCase();
return elements.filter(el =>
el.tagName.toLowerCase() === tagName.toLowerCase() &&
el.textContent.trim().toLowerCase().startsWith(lowerLetter)
);
}
const filteredLinks = filterByLetterAndType(focusableElements, 'm', 'a');
Такой подход позволяет создавать высоко специализированные механизмы поиска и навигации по интерфейсу, улучшая удобство работы с клавиатурой.
При больших списках элементов рекомендуется:
tabbable(container), обновляя их
только при изменении DOM.Эти методы обеспечивают быструю и отзывчивую работу интерфейсов с клавиатурой, особенно в сложных SPA или динамически генерируемых меню.