Как работает focusgroup и чем полезен?
• html
Введение
В последнее время активно разрабатывается новое АПИ про фокус и работу с клавиатурой. Если события beforefocus / focusreset и перемещения фокуса вперёд / назад ещё только в проработке, то новый атрибут focusgroup уже с нами с Хрома 150, а в данный момент в проработке находятся доработки к нему.
Что это за атрибут и в каких случаях может использоваться?
Задача
<div focusgroup="toolbar" aria-label="Форматирование текста">
<button type="button">Жирный</button>
<button type="button">Курсив</button>
<button type="button">Подчёркивание</button>
</div>При создании компонентов управления (контролов) часто встаёт задача сделать тулбар, меню и прочие группы вкладок. Обычно у подобных элементов есть стандартный подход к управлению с клавиатуры: у меню поддержка стрелок вверх-вниз, у вкладок – поддержка стрелок влево-вправо и так далее.
Чтобы всё это реализовать, обычно нужно исключить все фокусируемые элементы из общего обхода (через tabindex="-1") и навесить обработчиков на клавиатурное нажатия, перемещая фокус между элементами. Ну а активному элементу выставлять tabindex="0".
Есть и всевозможные дополнительные нюансы: нужно правильно обозначить роли для скринридеров, разметить активный элемент и так далее.
Учитывая, что все эти стандартные подходы в вебе встречаются не раз и не два, разработчики браузеров наконец представили нам “стандартный” способ сделать подобные элементы интерфейса через новый атрибут: focusgroup.
Focusgroup
Допустимые значения: toolbar, tablist, radiogroup, listbox, menu, menubar, none.
Как можно заметить, значения повторяют типичные интерфейсные шаблоны. Что даёт этот атрибут:
- Работу фокуса. При обычном обходе через
Tabфокус получит только один элемент, а остальные будут доступны через стрелки - Семантику для скринридеров. Причём это касается как контейнера, так и дочерних элементов
- Сохранение последнего элемента при обходе
- Различные пресеты настроек в зависимости от выбранного значения
Важный нюанс. Атрибут не влияет на выбор элемента, только на фокус! Это значит, что aria-selected и подобными вещами всё ещё нужно управлять самому!
Посмотрим более подробно на все функции. Кстати, есть большой список примеров, при желании можно обращаться к нему.
Направление контента
Часто подобные группы элементов расположены в виде горизонтальных и вертикальных списков. А новый атрибут позволяет задать направление через модификатор, который можно указать в атрибуте через пробел.
inline– дочерние элементы расположены по инлайновой оси (в нашем представлении это обычно горизонталь)block– дочерние элементы вдоль блочной оси
Итоговая конструкция выглядит так: focusgroup="toolbar inline".
Горизонтальный тулбар (inline)
Вертикальный тулбар (block)
Разные значения focusgroup имеют разные предустановки с направлениями. toolbar – инлайновое направление, menu – блочное.
Зацикленный обход
Ещё один модификатор – wrap. Он включён по умолчанию для значения tablist. Тем самым, при обходе элементов пользователь не упрётся в первый / последний элемент. Фокус в этом случае зацикленный.
Если же вы используете tablist, но вы хотите выключить зацикленный фокус, можно указать модификатор nowrap.
<div focusgroup="tablist nowrap">
...
</div>Стартовый элемент
С помощью атрибута focusgroupstart на дочернем элементе можно указать первый элемент в группе, который получит фокус.
<div focusgroup="tablist">
<button>Первая</button>
<button focusgroupstart>Вторая</button>
<button>Третья</button>
</div>При переходе фокуса в группу (как вперед через Tab, так и назад через Shift+Tab) фокус получит элемент с атрибутом focusgroupstart. Это может быть полезно, если выбран не первый элемент в группе (активная вкладка в момент загрузки страницы).
Сохранение выбранного элемента
По умолчанию, focusgroup запоминает активный элемент при уходе через Tab / Shift+Tab. Чтобы этого избежать, можно использовать модификатор nomemory:
<div focusgroup="tablist nomemory">
...
</div>Вложенные фокусгруппы
В более сложных случаях может потребоваться вложенная группа контролов:
<div focusgroup="toolbar">
<button>Кнопка 1</button>
<div focusgroup="toolbar">
<button>Вложено 1</button>
<button>Вложено 2</button>
</div>
<button>Кнопка 2</button>
</div>При таком использовании вложенная группа выступает, как большой элемент. Для перехода “внутрь” нужно использовать Tab, а не стрелки (и не Enter). А при перемещении табом через все элементы фокусируются элемент перед вложенной группой, элемент внутри вложенной группы, и элемент после вложенной группы. Это поведение выглядит не очень очевидно.
Исключение элементов из группы
С помощью значения focusgroup="none" можно исключить элементы из группы:
<div focusgroup="toolbar">
<button>Кнопка</button>
<div focusgroup="none">
<button>Кнопка</button>
<button>Кнопка</button>
</div>
<button>Кнопка</button>
</div>Это приводит к тому, что элементы внутри focusgroup="none" не получают фокус стрелками – их нужно фокусить через Tab.
Интеграция с reading-flow
CSS свойство reading-flow позволяет изменить порядок фокуса (например, в случае смены направления или использования order во флексбоксах).
Атрибут focusgroup гармонично интегрирован с reading-flow: порядок обхода группы такой же, как если бы был без группы.
Что дальше?
Файерфокс позитивно смотрит на focusgroup, а Сафари пока без ответа.
Но уже сейчас есть подвижки в сторону дополнительного функционала (FocusGroup V2):
- Модификатор
itemcontrolsвлияет на доступ к дочерним элементам - Пресеты
feedиgrid
Пока что эти возможности нигде не реализованы.
Итого
HTML делает огромный шаг навстречу типовым контролам. Количество кода, которое нужно для создания интерфейса, сокращается, а значит, и среднее качество интерфейсов в Интернете вырастет.
Мне очень нравится проработка этого АПИ: разные направления элементов, сохранение выбора, вложенные группы и другие возможности показывают, что простая идея обхода группы куда сложнее, чем кажется. Надеюсь, разработчики всё учли и в реальной жизни костыли не потребуются.
Ждём в Baseline 2027? Не уверен, особенно с Сафари.
Обсудить в Telegram



