Атрибут tabindex в HTML: порядок перехода по Tab

Атрибут tabindex управляет тем, попадает ли элемент в последовательный переход по клавише Tab, и в каком порядке. Это глобальный атрибут: его можно прописать на любом теге, включая те, что сами по себе с клавиатуры не фокусируются.

HTML
<div tabindex="0">Теперь сюда можно перейти по Tab</div>
<div>А сюда - нельзя, это обычный div</div>

Атрибут tabindex в HTML: что это и какие значения допустимы

Значение tabindex - целое число, и от его знака зависит поведение:

ЗначениеЧто происходит
Отрицательное (обычно -1)Элемент можно сфокусировать из кода (element.focus()) или кликом, но по Tab до него не дойти
0Элемент включается в Tab-переход, место в очереди - по порядку в разметке
Положительное (1-32767)Элемент получает фокус раньше всех нулевых и отрицательных, порядок - по возрастанию числа
Атрибут не указанБраузер сам решает, фокусируется элемент или нет - зависит от тега

У части тегов переход по Tab уже работает без всякого tabindex - у ссылки с href, у <button>, <input>, <select> и <textarea>. Прописывать им tabindex="0" незачем - он там и так есть по умолчанию. Исключение - <dialog>: на нём tabindex использовать не стоит вовсе, спецификация это отдельно оговаривает.

tabindex="-1": фокус по коду, но не по Tab

tabindex="-1" убирает элемент из очереди Tab, но не из фокуса вообще - на него всё ещё можно перевести фокус кодом через .focus() или кликом мышью. Типичный случай - сообщение об ошибке формы: пользователь не должен натыкаться на него клавишей Tab в обычной навигации, но после неудачной отправки формы фокус нужно сразу перевести на него, чтобы скринридер прочитал текст ошибки.

Пример: фокус на ошибке без участия в Tab-очереди

HTML + JavaScript
<p id="err" tabindex="-1">Заполните поле email</p>

if (!field.value) {
  err.hidden = false;
  err.focus();
}
Результат

После отправки пустой формы фокус кодом переводится на сообщение об ошибке - а следующий Tab пропускает его и уходит дальше по форме.

Почему tabindex больше нуля - плохая практика

Положительный tabindex выглядит как способ задать свой порядок перехода, но на практике ломает его: такие элементы получают фокус раньше всех остальных, причём по значению числа, а не по месту в разметке. Из-за этого порядок Tab перестаёт совпадать с тем, что видно на экране, и для человека, который ориентируется только по клавиатуре, страница превращается в головоломку.

Пример: положительный tabindex переставляет порядок

HTML
<button tabindex="3">Кнопка A</button>
<button tabindex="1">Кнопка B</button>
<button tabindex="0">Кнопка C</button>
<button tabindex="2">Кнопка D</button>
Результат

Кнопки идут в разметке A, B, C, D, но реальный порядок Tab - по возрастанию положительных значений, а нулевые уходят в самый конец.

Поэтому в руководствах по доступности положительные значения не рекомендуют вообще - для корректного порядка проще располагать элементы в разметке в том порядке, в котором они должны идти по Tab, и использовать только 0 и -1.

div с tabindex не становится кнопкой для скринридера

tabindex даёт элементу фокус, но не роль и не поведение. <div tabindex="0"> с обработчиком клика визуально ведёт себя как кнопка и получает фокус по Tab, но для скринридера это по-прежнему обычный безымянный блок, а не кнопка: он не объявит ни роль «кнопка», ни то, что элемент можно нажать пробелом или Enter - это поведение у <button> встроено, а у div его никто не добавляет автоматически.

HTML
<!-- так видит скринридер: безымянный блок -->
<div tabindex="0" onclick="save()">Сохранить</div>

<!-- так правильно: роль, поведение клавиатуры и фокус - всё уже есть -->
<button type="button" onclick="save()">Сохранить</button>

Если элемент должен вести себя как кнопка, ссылка или поле ввода, проще и надёжнее взять готовый тег с нужной семантикой, чем добавлять tabindex к div и достраивать роль и клавиатурные обработчики вручную.

Паттерн "подвижный tabindex" для групп виджетов

Когда на странице есть группа связанных элементов - например, переключатель размера текста или панель инструментов - Tab не должен останавливаться на каждом из них по отдельности: пользователю достаточно одной остановки на всей группе, а дальше переключаться стрелками. Для этого применяют паттерн roving tabindex («подвижный tabindex»): tabindex="0" есть только у одного, активного элемента группы, у всех остальных - tabindex="-1". При переключении стрелками значение tabindex="0" переставляется на новый активный элемент, а старый получает tabindex="-1".

Пример: переключение внутри группы без лишних остановок Tab

HTML + JavaScript
<div class="toolbar">
  <button tabindex="0">Маленький</button>
  <button tabindex="-1">Средний</button>
  <button tabindex="-1">Крупный</button>
</div>

// при переходе стрелкой на новую кнопку:
старыйАктив.tabIndex = -1;
новыйАктив.tabIndex = 0;
новыйАктив.focus();
Результат

Стрелками переключается активная кнопка внутри группы, а Tab заходит в группу один раз и сразу выходит за неё, к следующему элементу страницы.

Частые ошибки с атрибутом tabindex

С tabindex чаще путают не синтаксис, а то, что именно он даёт элементу и чего не даёт.

ОшибкаЧто происходитКак исправить
tabindex="0" прописывают ссылке, кнопке или полю вводаЭти теги и так в Tab-очереди по умолчанию - лишний tabindex ничего не меняет, только засоряет разметкуДобавлять tabindex только тем тегам, которые сами по себе не фокусируются
div с tabindex считают полноценной заменой buttonСкринридер не объявляет роль и не добавляет управление пробелом/Enter - это должен делать разработчик вручную, а у button оно уже естьИспользовать нативный <button> вместо div с tabindex, если нужна именно кнопка
Положительными значениями пытаются выстроить "правильный" порядокЭлементы с положительным tabindex выбиваются вперёд всех остальных по числу, а не по месту в разметке - порядок на экране и порядок Tab расходятсяРасполагать элементы в разметке в нужном порядке и использовать только 0 и -1
tabindex="-1" считают способом вообще убрать элемент из фокусаЭлемент всё ещё можно сфокусировать кодом или кликом - из Tab-очереди убирается только клавиатурный переход по порядкуДля полного исключения из фокуса нужны другие средства (disabled у полей форм, например)
Каждой кнопке тулбара прописывают свой tabindex="0"Tab останавливается на каждой кнопке по отдельности, хотя пользователю удобнее одна остановка и переключение стрелкамиПрименять паттерн roving tabindex - tabindex="0" только у активного элемента группы

Шпаргалка по атрибуту tabindex

ПравилоЧто запомнить
Где работаетНа любом теге (глобальный атрибут)
Отрицательное значениеФокус только кодом/кликом, вне Tab-очереди
0В Tab-очереди, порядок - по месту в разметке
Положительное значениеВ Tab-очереди раньше всех, порядок - по возрастанию числа
РекомендацияИспользовать только 0 и -1, положительных избегать
a[href]/button/input/select/textareaИ так в Tab-очереди без tabindex
<dialog>tabindex на нём не используют
div/span с tabindexПолучает фокус, но не роль и не клавиатурное поведение кнопки
Roving tabindextabindex="0" у одного активного элемента группы, у остальных -1; переключение - стрелками
Категория
Поделиться в социальных сетях

Отправить комментарий

0 Комментарии

Отправить комментарий (0)

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×