Ввод
Переключатели
Чекбокс, радио и свитч. Все три построены на нативном input: клавиатура,
отправка формы и скринридеры достаются бесплатно.
Разметка
<label class="inst-checkbox"><input type="checkbox" checked>Кешировать результат</label>
<label class="inst-radio"><input type="radio" name="mode" checked>Параллельно</label>
<label class="inst-radio"><input type="radio" name="mode">Последовательно</label>
<label class="inst-switch"><input type="checkbox" checked>Автозапуск</label>
Использование
Контрол лежит внутри <label>, поэтому for и id не нужны, а вся
подпись становится областью нажатия.
<label class="inst-checkbox">
<input type="checkbox" checked>
Кешировать результат
</label>
| Что | Обязательно | Почему |
|---|---|---|
<input> внутри <label> |
да | for и id не нужны, а областью нажатия становится вся подпись — единственный способ выполнить WCAG 2.5.8 при глифе в 15px |
Общий name у радиогруппы |
да | Без него варианты не взаимоисключающие, и клавиатурная навигация стрелками не заработает |
<fieldset> с <legend> вокруг радиогруппы |
да | Иначе скринридер прочитает варианты, но не вопрос |
Своего класса у input нет: он опознаётся по типу и родителю.
Когда использовать
| Возьмите другое | Когда |
|---|---|
| Сегментированный контрол | 2–4 варианта, и все должны быть видны разом |
| Селект | Больше пяти взаимоисключающих вариантов |
| Выбираемая карточка | У варианта есть описание, а не только подпись |
Варианты
Выбор между тремя не вкусовой — он про то, когда применяется значение.
Разметка
<label class="inst-checkbox"><input type="checkbox" checked>Чекбокс</label>
<label class="inst-radio"><input type="radio" name="v" checked>Радио</label>
<label class="inst-switch"><input type="checkbox" checked>Свитч</label>
| Когда | Применяется | |
|---|---|---|
| Чекбокс | Независимый флаг. Их может быть выбрано сколько угодно, включая ноль | По отправке формы |
| Радио | Один из нескольких взаимоисключающих. Выбран всегда ровно один | По отправке формы |
| Свитч | Включение и выключение режима | Немедленно, без кнопки «Применить» |
Состояния
Разметка
<label class="inst-checkbox"><input type="checkbox">Обычный</label>
<label class="inst-checkbox"><input type="checkbox" checked>Выбран</label>
<label class="inst-checkbox"><input type="checkbox" disabled>Недоступен</label>
<label class="inst-checkbox"><input type="checkbox" checked disabled>Выбран и недоступен</label>
Промежуточное состояние чекбокса — свойство indeterminate, оно ставится
только скриптом и не имеет атрибута в разметке:
el.indeterminate = true; // «часть вложенных выбрана»
Правила
Так Свитч применяется сразу
Рубильник, который уже сработал. Если состояние меняется в момент нажатия — это свитч.
Не так Свитч с кнопкой «Сохранить»
Он врёт: выглядит как сработавший рубильник, а значение ещё не применено. Если применение по отправке — это чекбокс.
Так Радио в fieldset с legend
Группа получает вопрос, на который отвечают варианты.
Не так Один радио без пары
У взаимоисключающего выбора не бывает одного варианта. Одна опция — это чекбокс или свитч.
Доступность
| Клавиатура | Space — переключение. Для радио: стрелки перебирают группу, Tab входит и выходит. Всё нативное, кит ничего не перехватывает |
| Область нажатия | Вся подпись, потому что контрол внутри <label>. Это единственный способ выполнить WCAG 2.5.8 при глифе в 15px |
| Группа радио | <fieldset> с <legend> даёт группе имя. Без него скринридер прочитает варианты, но не вопрос |
| Свитч | Нативный чекбокс. role="switch" можно добавить, если приложение хочет, чтобы состояние озвучивалось как «вкл/выкл», а не «отмечено» |
| Контраст | Рамка невыбранного берёт --border-control и держит 3:1: у всех трёх граница и есть контрол. У свитча к дорожке добавляется кольцо по той же причине |
| Не только цвет | Чекбокс несёт галочку, радио — точку, свитч — положение бегунка. Тон вторичен |
API
| Имя | Значение | Что делает |
|---|---|---|
| класс | ||
inst-checkbox | — | Обёртка-подпись чекбокса |
inst-radio | — | То же для радио |
inst-switch | — | То же для свитча |
| токен | ||
--size-check | 15px | |
--size-switch-w | 30px | |
--size-switch-h | 18px | |
--size-thumb | 14px | |
--border-control | light-dark(oklch(0 0 0 / 0.46), oklch(1 0 0 / 0.38)) | |
--accent-mark | light-dark(var(--a-4), var(--a-3)) | |
--accent-on | var(--n-0) | |
--track | light-dark(oklch(0 0 0 / 0.10), oklch(1 0 0 / 0.16)) | |
--radius-xs | 3px | |
--radius-full | 999px | |
--dur-1 | 80ms | |
Почему кит устроен именно так — конституция · Открытый код под MIT, github.com/keshon/instrument