GrCheckbox

  • ядро
  • Формы
  • API · 14 props
  • ⌨ клавиши

Берут, когда согласие или флаг в форме.

import { GrCheckbox } from '@feugene/granularity/components/GrCheckbox'

Обзор

Когда брать

  • согласие или флаг в форме — «запомнить меня», «согласен с условиями»: значение уедет с отправкой;
  • выбор строк списка — чекбокс в заголовке с indeterminate показывает частичный выбор;
  • подпись интерактивна — она живёт снаружи роли, поэтому ссылка внутри неё остаётся ссылкой;
  • нужна нативная форма — скрытый <input type="checkbox"> уходит с name и value.

Когда взять другое

НужноБерите
Настройка применяется немедленноGrSwitch
Вариантов несколько и они связаныGrCheckboxGroup
Можно выбрать только один вариантGrRadio
Переключаются режимы отображенияGrSegmented

Граница со GrSwitch проходит по моменту применения: чекбокс — значение формы, оно уезжает с сохранением; переключатель меняет состояние системы сразу, и кнопки «Сохранить» рядом с ним быть не должно.

Playground контролы выводятся из API, а не пишутся руками

Сцена

Загружается…

0 изменено· состояние — в адресе

Примеры 4 у каждого — живое демо и его код

  • Варианты, которые объясняют себя

    Подпись — содержимое самого флажка, поэтому имя с пояснением под ним — одна зона нажатия. Недоступный вариант сохраняет читаемый текст — состояния нарисованы токенами, а не прозрачностью, — ведь именно текст объясняет, почему варианта нет.

    Export SeptemberOne ZIP with a CSV per section
    Invoices418 documents with line items
    PaymentsMatched and unmatched
    Credit notes12 documents
    AttachmentsAvailable on the Business plan
  • Выбрать все, часть или ничего

    Флажок в заголовке вычисляется из строк: отмечен, когда отмечены все, пуст, когда ни одной, и indeterminate между ними — он нигде не хранится, поэтому не врёт. У строк нет видимой подписи, поэтому каждый флажок получает aria-label с номером счёта. Панель действий стоит всегда, и выбор не сдвигает список вниз.

    2 of 4 overdue invoices selected
    InvoiceCustomerDueAmount
    INV-0412Contoso LtdSep 30€432.00
    INV-0415Northwind TradersOct 2€1,284.50
    INV-0417Tailspin ToysOct 3€2,150.00
    INV-0419Fabrikam LogisticsOct 5€96.00
  • Матрица событий и каналов

    Каждая клетка — значение профиля, оно сохраняется вместе с ним, поэтому здесь флажки, а не переключатели. Заголовок колонки отмечает канал для всех событий и показывает indeterminate у частичной колонки; label-position="start" читает его как заголовок. Уведомления безопасности — readonly: состояние видно, но не меняется.

    NotificationsSaved with the profile · the column header switches a channel for every event
    Event
    Email
    Push
    Slack
    Invoice paid
    Invoice overdue
    Payment disputed
    Weekly summary
    Security notices · required

API порождается из пакета · разойтись не может

Props

PropTypeпо умолчаниюОписание
disabledboolean | undefinedundefinedНедоступен: не переключается и не фокусируется. Складывается по «или» с полем и группой.
modelValuev-modelboolean | undefinedundefinedНе задан внутри `GrCheckboxGroup` — состояние берётся из группы.
readonlyboolean | undefinedfalseТолько для чтения: состояние видно, но не переключается.
invalidboolean | undefinedfalseВизуальное и ARIA-состояние ошибки.
requiredboolean | undefinedfalseОбязательное поле: объявляется как `aria-required`, нативной проверки нет.
size"xs" | "sm" | "md" | "lg" | undefinedundefinedРазмер контрола. Не задан — берётся из группы, затем из `GrConfigProvider`, иначе `md`.
ariaLabelstring | undefinedundefinedИмя контрола, когда подписи в слоте нет (или она чисто визуальная).
namestring | undefinedundefinedИмя скрытого `<input>` в `FormData`. Внутри `GrCheckboxGroup` по умолчанию — имя группы.
valuestring | undefined"on"Значение для формы и ключ в массиве выбранных у `GrCheckboxGroup`. По умолчанию `on`.
idstring | undefinedundefinedПробрасывается на скрытый нативный `<input>`, чтобы работал `<label for="...">`.
tabindexnumber | undefinedundefinedОстановка `Tab` у самого переключателя. Нужна составным виджетам, которые забирают таб-порядок себе: в сетке `GrDataTable` (`cell-navigation`) `Tab` принадлежит таблице целиком, и чекбокс в ячейке своей остановки держать не должен — до него добираются стрелкой до ячейки и `Enter`. Выключенный переключатель остаётся вне обхода в любом случае.
formstring | undefinedundefinedId формы для скрытого `<input>`, когда чекбокс стоит вне её разметки.
indeterminateboolean | undefinedfalseПромежуточное («смешанное») состояние: `aria-checked="mixed"`, индикатор — тире.
labelPosition"end" | "start" | undefined"end"Сторона подписи относительно контрола.

Слоты

SlotTypeОписание
defaultanyПодпись флажка. Может содержать ссылки: роль остаётся на самом контроле.

События

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

GrCheckboxPropsinterface
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;
}
GrCheckboxEmitsinterface
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

grCheckboxConfigconst
const grCheckboxConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrCheckbox">;

Файлdist/types/components/GrCheckbox/defaults.d.ts

GrCheckboxConfigurablePropsinterface

Пропы GrCheckbox, настраиваемые глобально через <GrConfigProvider :component-defaults="{ GrCheckbox: { … } }">. Только оформление — см. GrButton/defaults.ts.

interface GrCheckboxConfigurableProps {
    size: GrCheckboxSize;
}

Файлdist/types/components/GrCheckbox/grCheckboxStyles.d.ts

GrCheckboxSizetype

Размерная шкала общая с формным рядом (GrRadio, GrInput, GrButton).

type GrCheckboxSize = GrButtonSize;
GrCheckboxLabelPositiontype
type GrCheckboxLabelPosition = typeof GR_CHECKBOX_LABEL_POSITIONS[number];

Файлdist/types/components/GrCheckbox/grCheckboxGroupContext.d.ts

GrCheckboxGroupContexttype
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

grCheckboxSafelistconst
const grCheckboxSafelist: string[];

Файлdist/types/components/GrCheckbox/index.d.ts

GrCheckboxInstancetype
type GrCheckboxInstance = ComponentExposed<typeof GrCheckboxComponent>;

Доступность

Паттерн APG

checkbox

Клавиши

Space

КлавишаДействие
Spaceпереключить (в т.ч. из indeterminate → включено)

Использование из прозы библиотеки

required объявляется, но не проверяется браузером

required доезжает до aria-required на span[role="checkbox"] и не выставляется на скрытом инпуте. Нативная проверка потребовала бы от браузера сфокусировать невалидный контрол, а он невидим и aria-hidden: Chrome в таком случае отменяет отправку всей формы и пишет в консоль «An invalid form control … is not focusable» — то есть required не мешал бы отправить, а ломал бы отправку молча.

Проверяет обязательность правило формы:

vue
<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 из контекста поля.