Checkbox Group
Typed multi-select group of native checkboxes with an optional tri-state select-all parent.
| Package | @vizejs/ui/checkbox-group |
| Maturity | stable |
| Own the source | vize lib pull checkbox-group |
| Requires | context, controllable-state |
| Aliases | checkbox list, multi-select checkboxes, select all, tri-state checkbox |
| Covers | HTML checkbox, WAI-ARIA Checkbox (tri-state), React Aria CheckboxGroup, Reka UI CheckboxGroup |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { CheckboxGroup, CheckboxGroupItem, CheckboxGroupSelectAll } from "@vizejs/ui/checkbox-group";
Or copy the source into your project with vize lib pull checkbox-group (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Typed topping selection with a tri-state select-all parent, bound with v-model. -->
<script setup lang="ts">
import { ref, useId } from "vue";
import { CheckboxGroup, CheckboxGroupItem, CheckboxGroupSelectAll } from "@vizejs/ui/checkbox-group";
const toppings = ["Mushrooms", "Olives", "Peppers", "Pineapple"];
const selected = ref<readonly string[]>(["Olives"]);
const baseId = useId();
</script>
<template>
<div>
<span :id="`${baseId}-legend`">Pizza toppings</span>
<CheckboxGroup
v-model="selected"
:options="toppings"
name="toppings"
:aria-labelledby="`${baseId}-legend`"
:is-option-disabled="(topping) => topping === 'Pineapple'"
>
<CheckboxGroupSelectAll :id="`${baseId}-all`" />
<label :for="`${baseId}-all`">Select all</label>
<template v-for="(topping, index) in toppings" :key="topping">
<CheckboxGroupItem :id="`${baseId}-${index}`" :value="topping" />
<label :for="`${baseId}-${index}`">{{ topping }}</label>
</template>
</CheckboxGroup>
<output>{{ selected.length ? selected.join(", ") : "No toppings" }}</output>
</div>
</template>
API
CheckboxGroup<Value>
Source: src/families/selection/checkbox-group/checkbox-group.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
options (required) |
readonly Value[] |
required |
Every selectable value, in display order. Infers the group's value type. |
modelValue |
readonly Value[] |
undefined |
Controlled selected values. undefined selects uncontrolled behavior. |
defaultValue |
readonly Value[] |
[] |
Initial uncontrolled selection, also restored by form reset. |
by |
(value: Value) => CheckboxGroupKey |
Object.is identity |
Identity key for comparing selected values with options, for example (user) => user.id when the model holds fresh object copies. |
getFormValue |
(value: Value, index: number) => string |
String(value) for primitives, else the option index |
Native form value submitted for an option. |
isOptionDisabled |
(value: Value, index: number) => boolean |
undefined |
Disable individual options. Disabled options keep their selection when select-all toggles. |
name |
string |
undefined |
Native form field name shared by every item checkbox. |
form |
string |
undefined |
Id of a form owner outside the component tree. |
disabled |
boolean |
false |
Disable every checkbox in the group. |
required |
boolean |
false |
Require at least one selection for native constraint validation. |
orientation |
CheckboxGroupOrientation |
"vertical" |
Layout direction published through data-orientation. |
ariaLabel |
string |
undefined |
Accessible name when no label or aria-labelledby supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the group. |
ariaDescribedby |
string |
undefined |
Space-separated ids that describe the group and every checkbox. |
ariaErrormessage |
string |
undefined |
Id of the validation error message used while invalid. |
ariaInvalid |
CheckboxGroupAriaInvalid |
false |
Invalid state announced on every checkbox. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue |
[value: readonly Value[]] |
Fired when the selection requests new values (in option order). |
change |
[value: readonly Value[], toggled: Value | null, selected: boolean] |
Fired after a user or API change with the next values, the toggled value (or null for select-all), and its new state. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
CheckboxGroupSlotState<Value> |
Renders items and the optional select-all parent with the selection summary. |
Exposed
| Member | Type | Description |
|---|---|---|
values |
readonly Value[] |
Selected values in option order. |
options |
readonly Value[] |
Every option, in order. |
allSelected |
boolean |
Whether every enabled option is selected. |
someSelected |
boolean |
Whether at least one but not every enabled option is selected. |
disabled |
boolean |
Whether the whole group is disabled. |
state |
CheckboxGroupState |
Selection summary. |
root |
HTMLDivElement | null |
Rendered group element. |
isSelected |
(value: Value) => boolean |
Whether an option value is selected. |
setSelected |
(value: Value, selected: boolean) => boolean |
Select or clear one option; returns whether the selection changed. |
setAll |
(selected: boolean) => boolean |
Select or clear every enabled option; returns whether the selection changed. |
reset |
() => boolean |
Restore the default selection; returns whether it changed. |
CheckboxGroupItem<Value>
Source: src/families/selection/checkbox-group/checkbox-group-item.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value (required) |
Value |
required |
Option this checkbox toggles; must be one of the group's options (by identity). |
id |
string |
undefined |
Native id, typically referenced by a <label for>. |
disabled |
boolean |
false |
Disable this checkbox in addition to group and isOptionDisabled rules. |
ariaLabel |
string |
undefined |
Accessible name when no wrapping or associated label supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label this checkbox. |
Events
| Event | Payload | Description |
|---|---|---|
change |
[checked: boolean, nativeEvent: Event] |
Fired after the user toggles this checkbox, with its new checked state and native Event. |
CheckboxGroupSelectAll
Source: src/families/selection/checkbox-group/checkbox-group-select-all.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string |
undefined |
Native id, typically referenced by a <label for>. |
ariaLabel |
string |
undefined |
Accessible name when no wrapping or associated label supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the parent checkbox. |
Events
| Event | Payload | Description |
|---|---|---|
change |
[selected: boolean, nativeEvent: Event] |
Fired after the user toggles every enabled option, with the requested state and native Event. |
Behavior
Normative state x input -> outcome table for checkbox-group.vue,
checkbox-group-item.vue, and checkbox-group-select-all.vue
(@vizejs/ui/checkbox-group). The group is generic: options: readonly Value[]
infers Value, so v-model is readonly Value[] for strings, unions, or
objects. The select-all parent follows the WAI-ARIA APG tri-state checkbox.
Every row is proven by the named test in checkbox-group.test.ts or
checkbox-group-ssr.test.ts; inference and misuse are pinned in
checkbox-group.types.test-d.ts.
| # | State | Input | Outcome | Proven by |
|---|---|---|---|---|
| C1 | named, seeded | render | labelled role="group" of native checkboxes sharing name; primitive options submit String(value); summary data-state and slot state |
renders a labelled group of named native checkboxes with typed values |
| C2 | uncontrolled objects | toggle items | values stay in option order, update:modelValue then change(values, toggled, selected); object options submit their index by default |
toggling items updates values in option order and emits changes |
| C3 | partial selection | select-all | parent is mixed/indeterminate while some enabled options are selected; toggling selects or clears enabled options and keeps disabled selections |
select-all is tri-state and toggles every enabled option |
| C4 | controlled with by |
toggle | fresh object copies match options by key; getFormValue controls submitted values; the controlled value wins until accepted |
controlled values win and `by` matches fresh object copies |
| C5 | in a form, required |
submit / toggle / reset | submits every selected value; every box is required only while nothing is selected; form reset restores defaultValue |
submits selected values, requires one selection, and restores defaults on reset |
| C6 | disabled group | toggle / API | every checkbox (and select-all) is natively disabled, aria-disabled on the group, and no changes are emitted |
disabled groups disable every checkbox and ignore toggles |
| C7 | imperative | expose | isSelected, setSelected (unknown values ignored), setAll, reset, and the selection summary |
exposes isSelected, setSelected, setAll, reset, and the selection summary |
| C8 | part without provider | setup | throws the stable VIZE_UI_CONTEXT_MISSING: CheckboxGroup diagnostic |
items and select-all require a CheckboxGroup provider |
| C9 | SSR / hydration | isolated requests | byte-identical markup (checked + aria-checked="mixed"), hydration applies indeterminate and stays interactive |
renders byte-identical checkbox group markup and hydrates without mismatches |
Public extension contract
| Surface | Contract |
|---|---|
| Parts | root (group), item, select-all (native checkboxes; wrap them in <label> for names). |
| Data attributes | data-vize-ui, root data-state (all/some/none/disabled), data-orientation; item data-index/data-state. |
| Identity | Items resolve value to an option by identity (through reactive proxies); by compares model values with options. |
The subpath is tree-shakable and ships no CSS; those package contracts are
pinned by distribution.test.ts, check:size, and check:tree-shaking.