Перейти к содержимому
Плотность
Тема

Действия

Группа кнопок

Несколько разных действий, поставленных вплотную. Группа говорит «эти действия про одно и то же», но каждое остаётся самостоятельным.

Компонент
Разметка
<div class="inst-btn-group">
  <button class="inst-btn inst-btn--sm" type="button">Слева</button>
  <button class="inst-btn inst-btn--sm" type="button">Центр</button>
  <button class="inst-btn inst-btn--sm" type="button">Справа</button>
</div>

Использование

Контейнер и обычные кнопки внутри. Группа не добавляет ролей: каждая кнопка объявляет себя сама — в этом и отличие от сегментированного контрола, где роль обязательна.

<div class="inst-btn-group">
  <button class="inst-btn" type="button">…</button>
  <button class="inst-btn" type="button">…</button>
</div>

Размер должен быть один на всю группу. Соседние кнопки разной высоты дают ступеньку на шве, и её видно на любом фоне.

Когда использовать

Используйте Возьмите другое
Разные действия над одним объектом: копировать · дублировать · удалить Выбор одного из равных вариантовсегментированный контрол. У группы нет выбранного элемента, и быть не может
Действие плюс его вариант: «Сохранить» и «Сохранить как» Список действий, который не влезаетменю в поповере
Панель инструментов, где кнопки сгруппированы по смыслу Разрозненные действиякластер с зазором: вплотную они соврут о родстве

Устройство

Шов группы — снятая рамка у соседа. Отрицательное поле в -0.5px не годится: браузер не рисует рамку тоньше физического пикселя, и сдвиг оставлял утолщение на каждом стыке.

Что делает контейнер Как
Снимает шов У всех кнопок, кроме первой, убирается ближняя рамка
Скругляет торцы Радиус остаётся только у первой и последней
Поднимает фокус Кнопка под фокусом идёт выше по z-index, иначе кольцо срезал бы сосед

Размеры

Размер задаётся каждой кнопке, а не контейнеру: группа не контрол, а композиция, и своего размера у неё нет.

Пример
Разметка
<div class="inst-btn-group">
  <button class="inst-btn inst-btn--sm" type="button">Один</button>
  <button class="inst-btn inst-btn--sm" type="button">Два</button>
</div>
<div class="inst-btn-group">
  <button class="inst-btn" type="button">Один</button>
  <button class="inst-btn" type="button">Два</button>
</div>
<div class="inst-btn-group">
  <button class="inst-btn inst-btn--lg" type="button">Один</button>
  <button class="inst-btn inst-btn--lg" type="button">Два</button>
</div>

Композиции

С иконочными кнопками

Пример
Разметка
<div class="inst-btn-group">
  <button class="inst-btn inst-btn--sm inst-btn--icon" type="button" aria-label="Обновить">
    <svg class="inst-icon" aria-hidden="true"><use href="#i-refresh"/></svg>
  </button>
  <button class="inst-btn inst-btn--sm inst-btn--icon" type="button" aria-label="Копировать">
    <svg class="inst-icon" aria-hidden="true"><use href="#i-copy"/></svg>
  </button>
  <button class="inst-btn inst-btn--sm inst-btn--icon" type="button" aria-label="Настройки">
    <svg class="inst-icon" aria-hidden="true"><use href="#i-settings"/></svg>
  </button>
</div>

Каждая иконочная кнопка несёт свой aria-label: у группы нет общего имени, потому что она не один контрол.

Сценарии

В тулбаре

Группы разделены зазором, внутри группы — вплотную. Зазор и есть сообщение о том, где кончается одно родство и начинается другое.

В контексте
Разметка
<div class="inst-toolbar">
  <div class="inst-btn-group">
    <button class="inst-btn inst-btn--sm" type="button">Список</button>
    <button class="inst-btn inst-btn--sm" type="button">Сетка</button>
  </div>
  <span class="inst-toolbar-sep"></span>
  <div class="inst-btn-group">
    <button class="inst-btn inst-btn--sm" type="button">Копировать</button>
    <button class="inst-btn inst-btn--sm" type="button">Дублировать</button>
  </div>
</div>

Правила

Так Один размер на группу

Все кнопки внутри одного размера. Разная высота даёт ступеньку на шве.

Не так Группа как выбор

У группы нет выбранного элемента. Если один из вариантов должен оставаться нажатым — это сегментированный контрол.

Так Tab по каждой кнопке

Это разные действия, и до каждого надо доходить с клавиатуры отдельно.

Не так Бегущий tabindex

tabindex="-1" у части кнопок спрятал бы действия от клавиатуры. Бегущий tabindex уместен там, где контрол один, — в сегментированном.

Доступность

Клавиатура Tab проходит по каждой кнопке отдельно — это разные действия, а не один выбор. Бегущий tabindex здесь был бы ошибкой: он спрятал бы часть действий от клавиатуры
Фокус Кнопка под фокусом поднимается по z-index, иначе кольцо срезал бы сосед. Элементы флекса подчиняются z-index без position
Имена Каждая кнопка несёт своё имя. Группа не нуждается в aria-label, потому что не является одним контролом

API

ИмяЗначениеЧто делает
класс
inst-btn-groupКонтейнер. Внутри — только inst-btn
токен
--radius-md7px
--hairline1px

Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument