Первый фокусируемый элемент

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

Ключевая цель Tabbable — возвращать массив элементов, которые могут быть «таб-ориентированными», исключая скрытые или заблокированные элементы. Это включает в себя <input>, <button>, <a> с атрибутом href, <select>, <textarea> и элементы с tabindex="0". Элементы с tabindex="-1" исключаются, так как они не участвуют в последовательности табуляции.


Определение первого фокусируемого элемента

Первый элемент для фокусировки важен для управления клавиатурной навигацией, особенно в модальных окнах, всплывающих меню или кастомных компонентах. Для получения такого элемента используется функция tabbable() библиотеки.

import tabbable from 'tabbable';

const container = document.querySelector('.modal');
const focusableElements = tabbable(container);

const firstFocusable = focusableElements[0];
firstFocusable.focus();

Пояснение:

  1. tabbable(container) возвращает массив всех элементов внутри container, доступных для табуляции.
  2. Первый элемент массива (focusableElements[0]) — это первый фокусируемый элемент.
  3. Метод .focus() устанавливает активный фокус на выбранный элемент.

Важно учитывать, что если массив пуст, вызов .focus() вызовет ошибку. Поэтому рекомендуется проверять наличие элементов:

if (focusableElements.length > 0) {
    focusableElements[0].focus();
}

Влияние атрибутов и стилей на табуляцию

Tabbable учитывает следующие факторы при определении фокусируемых элементов:

  • CSS-свойства: display: none, visibility: hidden и opacity: 0 исключают элемент из табуляции.

  • Атрибуты HTML:

    • disabled на <button>, <input>, <select>, <textarea> делает элемент недоступным для фокуса.
    • tabindex="-1" исключает элемент из последовательности табуляции.
  • Скрытые контейнеры: если родительский элемент имеет display: none, все вложенные элементы игнорируются.

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


Сценарии использования первого фокусируемого элемента

1. Модальные окна

При открытии модального окна первым фокусом обычно выбирается кнопка закрытия или первый интерактивный элемент:

const modal = document.querySelector('.modal');
const focusable = tabbable(modal);
if (focusable.length > 0) {
    focusable[0].focus();
}

2. Пользовательские панели и дропдауны

Для выпадающих меню важно автоматически устанавливать фокус на первый элемент списка, чтобы навигация клавиатурой была интуитивной.

3. Формы

В больших формах с множеством полей первый фокусируемый элемент — это обычно первое поле ввода, позволяющее пользователю сразу начинать работу без лишних кликов.


Оптимизация работы с фокусом

  • Кэширование результатов: если контейнер не изменяется динамически, можно сохранить массив фокусируемых элементов и повторно использовать его, избегая лишних вычислений.
  • Динамическое обновление: при добавлении новых элементов в DOM необходимо пересчитывать массив через tabbable(container), чтобы новый элемент мог быть выбран для фокуса.
  • Учет видимости: при динамическом скрытии элементов проверять их доступность перед установкой фокуса, чтобы избежать ошибок.

Примеры расширенного использования

Фокус на первом видимом элементе с определенным классом:

const container = document.querySelector('.form');
const firstButton = tabbable(container).find(el => el.classList.contains('primary'));
if (firstButton) {
    firstButton.focus();
}

Циклическая табуляция внутри модального окна:

const modal = document.querySelector('.modal');
const focusable = tabbable(modal);

modal.addEventListener('keydown', e => {
    if (e.key === 'Tab') {
        const index = focusable.indexOf(document.activeElement);
        if (e.shiftKey && index === 0) {
            e.preventDefault();
            focusable[focusable.length - 1].focus();
        } else if (!e.shiftKey && index === focusable.length - 1) {
            e.preventDefault();
            focusable[0].focus();
        }
    }
});

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


Tabbable позволяет детально контролировать порядок фокусировки и управлять первым элементом, на который будет установлен фокус. Благодаря простому API и встроенной фильтрации видимости и доступности элементов библиотека облегчает разработку доступных интерфейсов с корректной навигацией клавиатурой.