Фокус и tabindex

Модель фокуса в браузере и роль tabindex

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

Ключевые значения tabindex:

  • tabindex="0" — элемент участвует в естественном порядке фокуса
  • tabindex="-1" — элемент исключён из последовательного обхода, но может быть сфокусирован программно
  • tabindex=">0" — задаёт приоритет, но практически не рекомендуется из-за усложнения логики навигации

В контексте компонентов UI, особенно календарей, управление фокусом становится критичным для доступности и предсказуемого поведения интерфейса.


Поведение фокуса при инициализации Flatpickr

Flatpickr по умолчанию привязывается к текстовому input элементу. Этот элемент остаётся основным носителем фокуса, а сам календарный UI рендерится отдельно в DOM.

При инициализации:

  • фокус остаётся на input
  • календарь не перехватывает фокус автоматически
  • tabindex input определяется разработчиком или браузером

Это важное архитектурное решение: библиотека не ломает стандартный flow формы.


Открытие календаря и переключение фокуса

При открытии календаря (onOpen):

  • создаётся DOM-структура календаря
  • элементы дней становятся интерактивными
  • при этом фокус не обязан покидать input

Поведение управляется настройками:

  • static
  • appendTo
  • inline
  • disableMobile

Важный аспект

Flatpickr может работать в двух режимах:

  1. Overlay режим (по умолчанию)

    • календарь всплывает
    • фокус остаётся в input
    • навигация стрелками возможна без смены фокуса
  2. Inline режим

    • календарь всегда в DOM
    • фокус может переходить внутрь календаря
    • tabindex внутренних элементов становится критичнее

tabindex внутри календарной сетки

Внутренние элементы календаря (дни, стрелки, кнопки) получают динамический tabindex в зависимости от состояния.

Типичная логика:

  • активный день: tabindex="0"
  • неактивные дни: tabindex="-1"
  • кнопки навигации: tabindex="0" или управляемые через стрелочную навигацию

Это позволяет реализовать:

  • логичный порядок обхода
  • поддержку клавиатурной навигации
  • исключение «ловушек фокуса» при перемещении по датам

Управление фокусом через клавиатуру

Клавиатурная модель в Flatpickr строится вокруг стрелочной навигации, а не Tab-цепочки.

Основные принципы:

  • ArrowLeft / ArrowRight — перемещение по дням
  • ArrowUp / ArrowDown — переход по неделям
  • Enter — выбор даты
  • Escape — закрытие календаря

Tab используется минимально:

  • переход к следующему элементу формы
  • выход из календаря при закрытии

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


Фокус при выборе даты

После выбора даты поведение зависит от конфигурации:

  • стандартный режим:

    • выбранная дата записывается в input
    • фокус остаётся на input
  • с closeOnSelect: true:

    • календарь закрывается
    • фокус возвращается в input
  • с ручным управлением:

    • разработчик может переопределить onChange и onClose

Ключевой принцип — отсутствие неожиданного переноса фокуса без явного действия пользователя.


tabindex и disabled элементы

В календаре присутствуют неактивные дни (например, из соседних месяцев или запрещённые через disable).

Для них применяется:

  • aria-disabled="true"
  • tabindex="-1"

Это исключает их из Tab-последовательности и предотвращает случайное попадание фокуса.

Важно: визуальная доступность не должна вводить в заблуждение — элемент может быть видимым, но недоступным для фокуса.


Программное управление фокусом

Flatpickr предоставляет API, через которое можно управлять состоянием:

  • instance.open()
  • instance.close()
  • instance.jumpToDate(date)
  • instance.setDate(date)

При этом фокус можно контролировать вручную через стандартные DOM-методы:

input.focus();

или для календарных элементов:

const dayEl = calendar.querySelector('.flatpickr-day.selected');
dayEl?.focus();

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


tabindex в inline-режиме

В inline-режиме календарь становится частью постоянного DOM-потока.

Особенности:

  • элементы календаря участвуют в Tab-навигации
  • возрастает значение корректного tabindex
  • важно избегать дублирования фокуса с input

Рекомендуемая модель:

  • input остаётся точкой ввода
  • календарь — вспомогательная навигационная зона
  • Tab-цепочка минимальна внутри календаря

Фокус и динамическое обновление календаря

При смене месяца или года DOM пересобирается:

  • старые элементы уничтожаются
  • новые создаются заново
  • tabindex пересчитывается

Это означает:

  • ссылки на DOM-элементы нельзя кэшировать надолго
  • фокус может быть потерян при обновлении

Flatpickr обычно восстанавливает логический фокус через внутренний state, но кастомные модификации должны учитывать это поведение.


Типичные проблемы tabindex и фокуса

1. Потеря фокуса при кастомизации DOM

При модификации шаблона календаря возможно разрушение логики tabindex.

2. Конфликт с внешними tabindex

Если input имеет высокий tabindex, а календарь встроен, возможны неожиданные переходы Tab.

3. Ловушка фокуса

При неправильной обработке клавиатуры можно «застрять» внутри календаря без возможности выйти через Tab.

4. Несогласованность aria и tabindex

Если aria-disabled не совпадает с tabindex="-1", скринридеры и клавиатура начинают вести себя по-разному.


Рекомендации по архитектуре фокуса

  • input всегда остаётся главным фокусируемым элементом
  • календарь не должен перехватывать Tab-последовательность без необходимости
  • стрелочная навигация предпочтительнее Tab внутри календаря
  • tabindex="-1" используется для всех неактивных элементов
  • избегается ручная перенастройка tabindex после инициализации без необходимости

Связь фокуса с доступностью

Корректное управление tabindex напрямую влияет на:

  • работу скринридеров
  • предсказуемость клавиатурной навигации
  • соответствие WAI-ARIA практикам

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