Angular директивы

Библиотека Tabbable предназначена для определения элементов на странице, которые могут получать фокус при навигации с помощью клавиши Tab. Она обеспечивает точное и кроссбраузерное определение интерактивных элементов, учитывая атрибуты tabindex, видимость элементов и их состояние disabled.


Установка и импорт

Для использования Tabbable в проекте можно воспользоваться npm:

npm install tabbable

Импортируется библиотека следующим образом:

import { tabbable, isTabbable } from 'tabbable';
  • tabbable(container) – возвращает массив элементов, доступных для фокусировки внутри контейнера.
  • isTabbable(element) – проверяет, может ли конкретный элемент быть сфокусирован с помощью Tab.

Основные функции

tabbable(container)

Функция tabbable принимает DOM-элемент или document и возвращает все элементы, которые могут быть сфокусированы. Она учитывает:

  • Элементы <a> с атрибутом href.
  • Элементы <button>, <input>, <select>, <textarea>.
  • Элементы с положительным или нулевым tabindex.
  • Элементы, которые видимы на странице (display не none, visibility не hidden, непрозрачные и не скрытые родительскими элементами).

Пример использования:

const focusableElements = tabbable(document.body);
console.log(focusableElements);

Этот код вернёт массив всех элементов, доступных для табуляции на странице.


isTabbable(element)

Функция isTabbable позволяет проверить, может ли отдельный элемент получать фокус:

const button = document.querySelector('button');
if (isTabbable(button)) {
    console.log('Элемент доступен для фокуса');
}

Она возвращает булево значение, учитывая:

  • Атрибут disabled.
  • Видимость элемента.
  • Атрибут tabindex (отрицательные значения делают элемент недоступным для табуляции).

Управление порядком фокуса

Элементы с tabindex влияют на порядок обхода:

  • tabindex="0" – элемент включается в естественный порядок табуляции.
  • tabindex="-1" – элемент исключён из порядка табуляции, но доступен программно через focus().
  • tabindex="n" (положительное число) – элемент получает приоритет в обходе, с меньшими числами раньше.

Tabbable корректно учитывает этот порядок при формировании списка элементов.


Работа с Angular

В контексте 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();
  }
}

Этот подход особенно полезен для модальных окон и динамически создаваемых интерфейсов.


Важные нюансы

  • Скрытые элементы: Tabbable не включает элементы с display: none или visibility: hidden.
  • disabled элементы: кнопки и поля ввода с атрибутом disabled исключаются.
  • Shadow DOM: библиотека поддерживает поиск внутри Shadow DOM, если контейнер является хост-элементом.
  • Нестандартные элементы: элементы с 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 и доступности.