GrCheckbox
Берут, когда согласие или флаг в форме.
Обзор
Когда брать
- согласие или флаг в форме — «запомнить меня», «согласен с условиями»: значение уедет с отправкой;
- выбор строк списка — чекбокс в заголовке с
indeterminateпоказывает частичный выбор; - подпись интерактивна — она живёт снаружи роли, поэтому ссылка внутри неё остаётся ссылкой;
- нужна нативная форма — скрытый
<input type="checkbox">уходит сnameиvalue.
Когда взять другое
| Нужно | Берите |
|---|---|
| Настройка применяется немедленно | GrSwitch |
| Вариантов несколько и они связаны | GrCheckboxGroup |
| Можно выбрать только один вариант | GrRadio |
| Переключаются режимы отображения | GrSegmented |
Граница со GrSwitch проходит по моменту применения: чекбокс — значение
формы, оно уезжает с сохранением; переключатель меняет состояние системы
сразу, и кнопки «Сохранить» рядом с ним быть не должно.
Playground контролы выводятся из API, а не пишутся руками
Загружается…
0 изменено· состояние — в адресе
<GrCheckbox v-model="value">Email me when an invoice is paid</GrCheckbox>Примеры 4 у каждого — живое демо и его код
Согласие, без которого форма не уйдёт
required— правило,invalid— его вердикт, это два разных пропа. Отправьте форму, не отметив, — страница выставит вердикт, а пояснение под флажком станет ошибкой в той же строке, и форма не прыгнет. Ссылка внутри подписи остаётся ссылкой: клик по ней открывает условия, а не ставит галочку. ВнутриGrFormто же правило —validatorсvalue === true, потому что снятый флажок — законноеfalse.Варианты, которые объясняют себя
Подпись — содержимое самого флажка, поэтому имя с пояснением под ним — одна зона нажатия. Недоступный вариант сохраняет читаемый текст — состояния нарисованы токенами, а не прозрачностью, — ведь именно текст объясняет, почему варианта нет.
Export SeptemberOne ZIP with a CSV per section Invoices418 documents with line itemsPaymentsMatched and unmatchedCredit notes12 documentsAttachmentsAvailable on the Business planВыбрать все, часть или ничего
Флажок в заголовке вычисляется из строк: отмечен, когда отмечены все, пуст, когда ни одной, и
indeterminateмежду ними — он нигде не хранится, поэтому не врёт. У строк нет видимой подписи, поэтому каждый флажок получаетaria-labelс номером счёта. Панель действий стоит всегда, и выбор не сдвигает список вниз.2 of 4 overdue invoices selectedInvoiceCustomerDueAmountINV-0412Contoso LtdSep 30€432.00INV-0415Northwind TradersOct 2€1,284.50INV-0417Tailspin ToysOct 3€2,150.00INV-0419Fabrikam LogisticsOct 5€96.00Матрица событий и каналов
Каждая клетка — значение профиля, оно сохраняется вместе с ним, поэтому здесь флажки, а не переключатели. Заголовок колонки отмечает канал для всех событий и показывает
indeterminateу частичной колонки;label-position="start"читает его как заголовок. Уведомления безопасности —readonly: состояние видно, но не меняется.NotificationsSaved with the profile · the column header switches a channel for every event Event EmailPushSlackInvoice paid Invoice overdue Payment disputed Weekly summary Security notices · required
API порождается из пакета · разойтись не может
Props
| Prop | Type | по умолчанию | Описание |
|---|---|---|---|
disabled | boolean | undefined | undefined | Недоступен: не переключается и не фокусируется. Складывается по «или» с полем и группой. |
modelValuev-model | boolean | undefined | undefined | Не задан внутри `GrCheckboxGroup` — состояние берётся из группы. |
readonly | boolean | undefined | false | Только для чтения: состояние видно, но не переключается. |
invalid | boolean | undefined | false | Визуальное и ARIA-состояние ошибки. |
required | boolean | undefined | false | Обязательное поле: объявляется как `aria-required`, нативной проверки нет. |
size | "xs" | "sm" | "md" | "lg" | undefined | undefined | Размер контрола. Не задан — берётся из группы, затем из `GrConfigProvider`, иначе `md`. |
ariaLabel | string | undefined | undefined | Имя контрола, когда подписи в слоте нет (или она чисто визуальная). |
name | string | undefined | undefined | Имя скрытого `<input>` в `FormData`. Внутри `GrCheckboxGroup` по умолчанию — имя группы. |
value | string | undefined | "on" | Значение для формы и ключ в массиве выбранных у `GrCheckboxGroup`. По умолчанию `on`. |
id | string | undefined | undefined | Пробрасывается на скрытый нативный `<input>`, чтобы работал `<label for="...">`. |
tabindex | number | undefined | undefined | Остановка `Tab` у самого переключателя. Нужна составным виджетам, которые забирают таб-порядок себе: в сетке `GrDataTable` (`cell-navigation`) `Tab` принадлежит таблице целиком, и чекбокс в ячейке своей остановки держать не должен — до него добираются стрелкой до ячейки и `Enter`. Выключенный переключатель остаётся вне обхода в любом случае. |
form | string | undefined | undefined | Id формы для скрытого `<input>`, когда чекбокс стоит вне её разметки. |
indeterminate | boolean | undefined | false | Промежуточное («смешанное») состояние: `aria-checked="mixed"`, индикатор — тире. |
labelPosition | "end" | "start" | undefined | "end" | Сторона подписи относительно контрола. |
Слоты
| Slot | Type | Описание |
|---|---|---|
default | any | Подпись флажка. Может содержать ссылки: роль остаётся на самом контроле. |
События
| Event | Сигнатура | Описание |
|---|---|---|
update:modelValue | (event: "update:modelValue", value: boolean): void | — |
change | (event: "change", value: boolean): void | — |
focus | (event: "focus", event: FocusEvent): void | — |
blur | (event: "blur", event: FocusEvent): void | — |
Методы
| Methods | Сигнатура | Описание |
|---|---|---|
focus | () => void | Поставить фокус на контрол — тот же, что получает `Tab`. |
blur | () => void | Снять фокус с контрола. |
Типы
Все экспортируемые типы подпути, по файлам, где они объявлены. Имена, дженерики и тела читаются из файлов деклараций пакета и разойтись не могут.
import type { GrCheckboxProps, GrCheckboxEmits, GrCheckboxConfigurableProps } from '@feugene/granularity/components/GrCheckbox'Файлdist/types/components/GrCheckbox/GrCheckbox.vue.d.ts
interface GrCheckboxProps {
/**
* Остановка `Tab` у самого переключателя.
*
* Нужна составным виджетам, которые забирают таб-порядок себе: в сетке
* `GrDataTable` (`cell-navigation`) `Tab` принадлежит таблице целиком, и
* чекбокс в ячейке своей остановки держать не должен — до него добираются
* стрелкой до ячейки и `Enter`. Выключенный переключатель остаётся вне
* обхода в любом случае.
*/
tabindex?: number;
/** Не задан внутри `GrCheckboxGroup` — состояние берётся из группы. */
modelValue?: boolean;
/** Недоступен: не переключается и не фокусируется. Складывается по «или» с полем и группой. */
disabled?: boolean;
/** Имя скрытого `<input>` в `FormData`. Внутри `GrCheckboxGroup` по умолчанию — имя группы. */
name?: string;
/** Значение для формы и ключ в массиве выбранных у `GrCheckboxGroup`. По умолчанию `on`. */
value?: string;
/** Обязательное поле: объявляется как `aria-required`, нативной проверки нет. */
required?: boolean;
/** Только для чтения: состояние видно, но не переключается. */
readonly?: boolean;
/** Визуальное и ARIA-состояние ошибки. */
invalid?: boolean;
/** Id формы для скрытого `<input>`, когда чекбокс стоит вне её разметки. */
form?: string;
/** Пробрасывается на скрытый нативный `<input>`, чтобы работал `<label for="...">`. */
id?: string;
/** Промежуточное («смешанное») состояние: `aria-checked="mixed"`, индикатор — тире. */
indeterminate?: boolean;
/** Имя контрола, когда подписи в слоте нет (или она чисто визуальная). */
ariaLabel?: string;
/** Сторона подписи относительно контрола. */
labelPosition?: GrCheckboxLabelPosition;
/** Размер контрола. Не задан — берётся из группы, затем из `GrConfigProvider`, иначе `md`. */
size?: GrCheckboxSize;
}interface GrCheckboxEmits {
/**
* Новое состояние для `v-model`. Внутри группы без своего `modelValue` не шлётся —
* значение уходит в группу.
*/
(e: 'update:modelValue', value: boolean): void;
/** Пользователь переключил чекбокс; шлётся и внутри `GrCheckboxGroup`. */
(e: 'change', value: boolean): void;
/** Фокус пришёл на контрол — в том числе кликом по внешнему `<label for>`. */
(e: 'focus', event: FocusEvent): void;
/** Фокус ушёл с контрола. */
(e: 'blur', event: FocusEvent): void;
}Файлdist/types/components/GrCheckbox/config.d.ts
const grCheckboxConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrCheckbox">;Файлdist/types/components/GrCheckbox/defaults.d.ts
Пропы GrCheckbox, настраиваемые глобально через
<GrConfigProvider :component-defaults="{ GrCheckbox: { … } }">.
Только оформление — см. GrButton/defaults.ts.
interface GrCheckboxConfigurableProps {
size: GrCheckboxSize;
}Файлdist/types/components/GrCheckbox/grCheckboxStyles.d.ts
Размерная шкала общая с формным рядом (GrRadio, GrInput, GrButton).
type GrCheckboxSize = GrButtonSize;type GrCheckboxLabelPosition = typeof GR_CHECKBOX_LABEL_POSITIONS[number];Файлdist/types/components/GrCheckbox/grCheckboxGroupContext.d.ts
type GrCheckboxGroupContext = {
/** Выбранные значения группы. Чекбокс сравнивает с ними свой `value`. */
modelValue: ComputedRef<string[]>;
name: ComputedRef<string | undefined>;
disabled: ComputedRef<boolean>;
readonly: ComputedRef<boolean>;
invalid: ComputedRef<boolean>;
/**
* Обязательность группы объявляют её чекбоксы: `role="group"` не поддерживает
* `aria-required` (axe: `aria-allowed-attr`), а `role="checkbox"` — да.
*/
required: ComputedRef<boolean>;
size: ComputedRef<GrCheckboxSize>;
/** Добавляет или убирает значение из выбранных. */
toggle: (value: string, checked: boolean) => void;Файлdist/types/components/GrCheckbox/safelist.d.ts
const grCheckboxSafelist: string[];Файлdist/types/components/GrCheckbox/index.d.ts
type GrCheckboxInstance = ComponentExposed<typeof GrCheckboxComponent>;Доступность
Паттерн APG
checkbox
Клавиши
Space
| Клавиша | Действие |
|---|---|
| Space | переключить (в т.ч. из indeterminate → включено) |
Полный контракт пакета: docs/keyboard.md ↗
Использование из прозы библиотеки
required объявляется, но не проверяется браузером
required доезжает до aria-required на span[role="checkbox"] и не
выставляется на скрытом инпуте. Нативная проверка потребовала бы от браузера
сфокусировать невалидный контрол, а он невидим и aria-hidden: Chrome в таком
случае отменяет отправку всей формы и пишет в консоль «An invalid form control
… is not focusable» — то есть required не мешал бы отправить, а ломал бы
отправку молча.
Проверяет обязательность правило формы:
<script setup lang="ts">
// `required` пустым считает `null`/`''`/`[]`, но не `false`: снятый чекбокс —
// это законное значение поля. «Согласие обязательно» — это `validator`.
const rules: GrFormRules = {
terms: [{ validator: value => value === true || 'Примите условия' }],
}
</script>
<template>
<GrForm :model="model" :rules="rules">
<GrFormField name="terms" label="Условия">
<GrCheckbox v-model="model.terms" required />
</GrFormField>
</GrForm>
</template>Подпись живёт снаружи роли-виджета
role="checkbox" объявляет своих потомков презентационными, поэтому внутри него
нет ни нативного инпута, ни содержимого слота: имя виджета приходит через
aria-labelledby. Ради этого подпись и вынесена наружу — она может содержать
ссылку на политику или кнопку «показать изменения».
Следствие: клик по подписи чекбокс переключает, а клик по её интерактивному
содержимому (a, button, input, select, textarea, вложенный label,
[role="button"], [role="link"]) — нет, такой элемент адресует сам себя.
labelPosition="start" ставит подпись перед контролом.
Состояния
disabled и invalid показываются токенами фона и рамки, а не прозрачностью:
opacity разбавляет выверенные на AA токены текста. readonly оставляет
значение в форме и возвращает нативный инпут к модели, если его переключил клик
по внешнему <label for>.
Внутри GrFormField контрол получает id на виджет, aria-describedby,
aria-invalid и aria-required из контекста поля.
Пропы этого примера