Библиотека Tabbable предназначена для определения
элементов на странице, которые могут получать фокус при навигации с
помощью клавиши Tab. Она обеспечивает точное и
кроссбраузерное определение интерактивных элементов, учитывая атрибуты
tabindex, видимость элементов и их состояние
disabled.
Для использования Tabbable в проекте можно воспользоваться npm:
npm install tabbable
Импортируется библиотека следующим образом:
import { tabbable, isTabbable } from 'tabbable';
tabbable(container) – возвращает
массив элементов, доступных для фокусировки внутри контейнера.isTabbable(element) – проверяет, может
ли конкретный элемент быть сфокусирован с помощью Tab.Функция tabbable принимает DOM-элемент или
document и возвращает все элементы, которые могут быть
сфокусированы. Она учитывает:
<a> с атрибутом href.<button>, <input>,
<select>, <textarea>.tabindex.display не
none, visibility не hidden,
непрозрачные и не скрытые родительскими элементами).Пример использования:
const focusableElements = tabbable(document.body);
console.log(focusableElements);
Этот код вернёт массив всех элементов, доступных для табуляции на странице.
Функция isTabbable позволяет проверить, может ли отдельный элемент получать фокус:
const button = document.querySelector('button');
if (isTabbable(button)) {
console.log('Элемент доступен для фокуса');
}
Она возвращает булево значение, учитывая:
disabled.tabindex (отрицательные значения делают элемент
недоступным для табуляции).Элементы с tabindex влияют на порядок обхода:
tabindex="0" – элемент включается в естественный
порядок табуляции.tabindex="-1" – элемент исключён из порядка табуляции,
но доступен программно через focus().tabindex="n" (положительное число) – элемент получает
приоритет в обходе, с меньшими числами раньше.Tabbable корректно учитывает этот порядок при формировании списка элементов.
В контексте Angular библиотека Tabbable используется для управления фокусом в директивах и компонентах.
import { Directive, ElementRef, AfterViewInit } from '@angular/core';
import { tabbable } from 'tabbable';
@Directive({
selector: '[appFocusable]'
})
export class FocusableDirective implements AfterViewInit {
constructor(private el: ElementRef) {}
ngAfterViewInit() {
const elements = tabbable(this.el.nativeElement);
console.log('Доступные элементы для фокуса:', elements);
}
}
Эта директива позволяет внутри контейнера автоматически получать все табулируемые элементы и управлять ими.
Для UX часто требуется автоматически ставить фокус на первый интерактивный элемент:
import { Component, AfterViewInit, ElementRef } from '@angular/core';
import { tabbable } from 'tabbable';
@Component({
selector: 'app-modal',
template: `
<div #modal>
<input type="text" />
<button>Сохранить</button>
</div>
`
})
export class ModalComponent implements AfterViewInit {
constructor(private el: ElementRef) {}
ngAfterViewInit() {
const firstFocusable = tabbable(this.el.nativeElement)[0];
if (firstFocusable) firstFocusable.focus();
}
}
Этот подход особенно полезен для модальных окон и динамически создаваемых интерфейсов.
display: none или visibility: hidden.disabled исключаются.contenteditable могут быть включены в обход табуляции.Можно фильтровать элементы по классам или атрибутам:
const tabbableInputs = tabbable(document.body).filter(el => el.tagName === 'INPUT');
Tabbable часто используется для реализации focus trap, когда фокус ограничен внутри модального окна:
function trapFocus(modal) {
const elements = tabbable(modal);
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
const first = elements[0];
const last = elements[elements.length - 1];
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
}
Это позволяет циклически обходить интерактивные элементы внутри контейнера без выхода фокуса наружу.
Tabbable является мощным инструментом для управления фокусом, особенно в современных SPA и приложениях на Angular, обеспечивая корректное и предсказуемое поведение клавиатурной навигации. Она сочетает простоту использования с полной поддержкой стандартов HTML и доступности.