GrCheckboxGroup

  • core
  • forms
  • API · 10 props
  • ⌨ keys

Collects checkboxes into one multi-select field with a shared model and states.

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

Overview

When to take it

  • several values out of a short set — permissions, tags, days of the week, notification channels;
  • every option has to be visible — the selection is seen as a whole, without opening a panel;
  • the group is part of a form — a shared string[] model, shared disabled, readonly and invalid;
  • there are up to a dozen options — beyond that the list grows longer than the screen.

When to take something else

NeedTake
There are many optionsGrSelect with multiple
There are many options and they are searched by typingGrAutocomplete
Only one can be selectedGrRadioGroup
There is a single checkboxGrCheckbox
The options are nestedGrTreeSelect

Playground controls come from the API, not from hand

Stage

Loading…

0 changed· state is in the URL

Examples 4 each with a live demo and its code

  • Permissions of a role, area by area

    Each area is a group with its own string[], and the group hands the selection, name and states down to its checkboxes — none of them needs a v-model. An option’s disabled beats an enabled group: voiding issued invoices stays with the owner, and the label says so.

    Role · Accountant3 members · 5 of 7 permissions
    Invoices
    View invoices
    Create and edit drafts
    Send to customers
    Void issued invoices · owner only
    Payments
    View payments
    Match bank transfers
    Issue refunds
  • A filter with counts

    When a row needs more than a label, the default slot replaces options: each GrCheckbox gets only a value, and the group gives it the rest. Here every status carries its count, and the total under the list follows the selection.

    Status
    Open48
    Waiting on customer23
    On hold6
    Solved this week131
    71 tickets in the queue
  • A review that turns into an edit

    readonly on the group keeps the choice visible and in the form, but not switchable — the renewal is reviewed, not edited, until «Change». The state belongs to the group and reaches every checkbox; nothing moves when it flips.

    Renewal · add-onsBusiness plan renews on 1 November
    Single sign-on€120 a month
    Audit log export€60 a month
    Sandbox workspace€45 a month
    Priority support€200 a month
    Add-ons on the next invoice€320 a month
  • Days of the week in a row

    direction="horizontal" suits seven short labels. required announces the rule, and invalid marks the group as a whole — «at least one day» is broken by the set, not by a single box, so the error is announced once, not seven times.

    Café Lumen · deliveriesBread arrives before 7:00 on the chosen days
    Delivery days
    Mon
    Tue
    Wed
    Thu
    Fri
    Sat
    Sun
    3 deliveries a week

API generated from the package · cannot drift

Props

PropTypedefaultDescription
disabledboolean | undefinedfalseDisable the whole group. Combined with `disabled` of `GrFormField`.
optionsGrCheckboxGroupOption[] | undefinedundefinedThe options from which the group builds the checkboxes. Not needed if the checkboxes are laid out in the slot.
readonlyboolean | undefinedfalseRead-only: the selection is visible but does not change.
invalidboolean | undefinedfalseThe visual and ARIA state of an error for the whole group.
requiredboolean | undefinedfalseA required group: `aria-required` is announced by the checkboxes themselves.
size"xs" | "sm" | "md" | "lg" | undefinedundefinedThe size step of the checkboxes in the group. `md` by default; taken from `GrConfigProvider`.
ariaLabelstring | undefinedundefinedThe accessible name of the group. If not set, the name is taken from the label of `GrFormField`.
namestring | undefinedundefinedA shared name for a native form: the values leave as repeated fields.
directionGrCheckboxGroupDirection | undefined"vertical"The layout: `vertical` — in a column, `horizontal` — in a row with wrapping. `vertical` by default.
modelValuerequiredv-modelstring[]—The checked values (`v-model`): every checkbox in the group has its own `value`.

Slots

SlotTypeDescription
defaultanyMarkup of your own for the checkboxes instead of generating them from `options`.

Events

EventSignatureDescription
update:modelValue(event: "update:modelValue", value: string[]): void—
change(event: "change", value: string[]): void—
focus(event: "focus", event: FocusEvent): void—
blur(event: "blur", event: FocusEvent): void—

Methods

MethodsSignatureDescription
focus() => voidPut focus on the first available checkbox of the group.
blur() => voidRemove focus from the first available checkbox — the counterpart of `focus`.

Types

Every exported type of the subpath, grouped by the file it lives in. Names, generics and bodies come from the package’s declaration files and cannot drift.

Import
import type { GrCheckboxGroupConfigurableProps, GrCheckboxGroupDirection, GrCheckboxGroupOption } from '@feugene/granularity/components/GrCheckboxGroup'

Filedist/types/components/GrCheckboxGroup/config.d.ts

grCheckboxGroupConfigconst
const grCheckboxGroupConfig: import("@feugene/granum/contract").GranumComponentDescriptor<"GrCheckboxGroup">;

Filedist/types/components/GrCheckboxGroup/defaults.d.ts

GrCheckboxGroupConfigurablePropsinterface
interface GrCheckboxGroupConfigurableProps {
    size: GrCheckboxSize;
}

Filedist/types/components/GrCheckboxGroup/GrCheckboxGroup.vue.d.ts

GrCheckboxGroupDirectiontype
type GrCheckboxGroupDirection = 'vertical' | 'horizontal';
GrCheckboxGroupOptioninterface
interface GrCheckboxGroupOption {
    value: string;
    label: string;
    disabled?: boolean;
}
GrCheckboxGroupPropsinterface
interface GrCheckboxGroupProps {
    modelValue: string[];
    options?: GrCheckboxGroupOption[];
    name?: string;
    disabled?: boolean;
    readonly?: boolean;
    invalid?: boolean;
    required?: boolean;
    direction?: GrCheckboxGroupDirection;
    size?: GrCheckboxSize;
    ariaLabel?: string;
}
GrCheckboxGroupEmitsinterface
interface GrCheckboxGroupEmits {
    (e: 'update:modelValue', value: string[]): void;
    (e: 'change', value: string[]): void;
    (e: 'focus', event: FocusEvent): void;
    (e: 'blur', event: FocusEvent): void;
}

Filedist/types/components/GrCheckboxGroup/index.d.ts

GrCheckboxGroupInstancetype
type GrCheckboxGroupInstance = ComponentExposed<typeof GrCheckboxGroupComponent>;

Accessibility

APG pattern

group

Usage from the library prose

The model and the context

The group hands the nested checkboxes the selected values, name, size and the disabled/readonly/invalid states, so they need no v-model of their own — value is enough:

vue
<GrCheckboxGroup v-model="channels" name="channels" :options="options" />

<GrCheckboxGroup v-model="channels" direction="horizontal">
  <GrCheckbox value="sms">SMS</GrCheckbox>
  <GrCheckbox value="email">Email</GrCheckbox>
</GrCheckboxGroup>

name goes to every checked checkbox, so a native form gets a repeated field: new FormData(form).getAll('channels').

The disabled of an individual option beats an enabled group. A value in the model that is not among the options is not lost by the group: unchecking a neighbouring checkbox keeps it.

The role and ARIA

role="group", not radiogroup: checkboxes have no roving tabindex and no moving of the selection with the arrows — each stays a Tab stop of its own, exactly like a set of native <input type="checkbox">.

role="group" does not support aria-required and aria-readonly (axe reports that as a critical aria-allowed-attr), so both states are declared by the checkboxes themselves. aria-invalid, on the contrary, hangs on the group alone: duplicated on every item, it would make a screen reader repeat “invalid value” as many times as there are checkboxes in the group — on an error the items are merely recoloured.

Being required

As with a single checkbox, required is a declaration; a form rule does the checking. For a group the built-in required works: an empty array counts as an empty value.

ts
const rules: GrFormRules = {
  channels: [{ required: true, message: 'Choose at least one channel' }],
}