Условная активация

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

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

Ключевые функции и методы

  1. tabbable(container) Возвращает массив всех табулируемых элементов внутри указанного контейнера. По умолчанию ищет элементы по всему DOM, если контейнер не указан.

    import tabbable from 'tabbable';
    
    const container = document.getElementById('form-section');
    const elements = tabbable(container);
    console.log(elements); // [input, button, select, ...]
  2. focusable(container) Отличается от tabbable тем, что возвращает все элементы, которые могут получать фокус программно, даже если они не включены в естественный порядок табуляции.

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

Управление порядком табуляции

Элементы с положительным tabindex получают приоритет при навигации с помощью Tab. Tabbable учитывает этот порядок и возвращает элементы строго в соответствии с правилами спецификации HTML:

  • tabindex="0" — элемент участвует в обычном порядке табуляции.
  • tabindex="-1" — элемент фокусируется только программно, через element.focus().
  • tabindex="N" (N > 0) — элемент получает приоритет перед элементами с tabindex="0" в порядке возрастания N.

Это позволяет реализовать условную активацию элементов, когда видимость или доступность элемента меняется динамически.

Условная активация элементов

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

Примеры условий:

  1. Элемент видим только при открытом модальном окне

    const modal = document.getElementById('modal');
    const inputs = tabbable(modal);
    
    if (modal.classList.contains('open')) {
        inputs.forEach(input => input.removeAttribute('disabled'));
    } else {
        inputs.forEach(input => input.setAttribute('disabled', true));
    }
  2. Активация по состоянию формы

    Элементы могут быть активированы в зависимости от заполненности других полей:

    const submitButton = document.getElementById('submit');
    const requiredInput = document.getElementById('username');
    
    requiredInput.addEventListener('input', () => {
        if (requiredInput.value.trim() !== '') {
            submitButton.removeAttribute('disabled');
        } else {
            submitButton.setAttribute('disabled', true);
        }
    });
  3. Динамическое управление tabindex

    Позволяет полностью контролировать порядок фокуса:

    const dynamicFields = document.querySelectorAll('.dynamic-field');
    
    dynamicFields.forEach((field, index) => {
        field.tabIndex = index % 2 === 0 ? 0 : -1; // фокусируются только чётные элементы
    });

Особенности использования с современными фреймворками

В библиотеках вроде React или Vue Tabbable интегрируется через рефы или ссылки на DOM-элементы. Основные моменты:

  • Массив табулируемых элементов обновляется при монтировании и размонтировании компонентов.
  • Для модальных окон или скрываемых панелей важно пересчитывать табулируемые элементы при изменении видимости.
  • Использование useEffect или watch позволяет динамически управлять фокусом и состоянием disabled/tabindex.
import { useEffect, useRef } from 'react';
import tabbable from 'tabbable';

function Modal({ isOpen }) {
    const modalRef = useRef(null);

    useEffect(() => {
        if (isOpen && modalRef.current) {
            const elements = tabbable(modalRef.current);
            elements[0]?.focus();
        }
    }, [isOpen]);

    return (
        <div ref={modalRef} className={isOpen ? 'open' : 'closed'}>
            <input type="text" />
            <button>Submit</button>
        </div>
    );
}

Практические рекомендации

  • Для сложных интерфейсов рекомендуется пересчитывать табулируемые элементы после каждого изменения DOM, влияющего на доступность.
  • Не использовать отрицательные tabindex для элементов, которые должны быть доступны пользователю по Tab, если нет строгой необходимости.
  • Комбинировать Tabbable с ARIA-атрибутами (aria-hidden, aria-disabled) для обеспечения доступности.
  • Для динамических списков и модальных окон использовать программное управление фокусом и условное включение/отключение элементов.

Tabbable обеспечивает точное управление навигацией по интерфейсу, позволяя реализовать гибкие сценарии условной активации и повышать доступность веб-приложений.