Checklist — Guidelines
When to use
| Pattern | Use |
|---|---|
catnip-checklist | Labelled multi-select from an options array (Figma checkbox Examples). |
catnip-checkbox alone | Single option, consent, or a row you place yourself outside a checklist. |
catnip-dropdown multiple | Many options in a compact panel; checkbox chrome is internal. |
Binding
vue
<catnip-checklist
label="Choose multiple"
required
intent="danger"
supporting-text="Resolve the option-level errors below."
.options="options"
.modelValue="selected"
@update:modelValue="selected = $event.detail[0] ?? $event.detail"
/>js
const selected = ref(["a", "b"]);
const options = ref([
{ value: "a", label: "Option A" },
{
value: "b",
label: "Option B",
intent: "danger",
supportingText: "Cannot be selected together with Option A."
},
{ value: "c", label: "Option C" }
]);Bind .options and .modelValue on the host (see Component API).
Validation (group + per option)
Use two levels:
| Level | Set on | Example |
|---|---|---|
| Group | catnip-checklist → intent, supporting-text | “Select at least one option.” |
| Row | Each options[] item → intent, supportingText | “Cannot be selected with Option A.” |
Per-row intent is only neutral or danger (same as catnip-checkbox). Group intent also supports warning and success for the field supporting-text block.
Static row errors
Put intent and supportingText directly on the option object (see live playground — Option B shows a row error while A and B are selected).
Dynamic row errors (your app updates options)
Recompute the options array when selection or server validation changes:
js
import { computed, ref } from "vue";
const selected = ref([]);
const baseOptions = [
{ value: "a", label: "Option A" },
{ value: "b", label: "Option B" },
{ value: "c", label: "Option C" }
];
const options = computed(() => {
const hasA = selected.value.includes("a");
const hasB = selected.value.includes("b");
const conflict = hasA && hasB;
return baseOptions.map((opt) => {
if (opt.value !== "b") return opt;
if (!conflict) return opt;
return {
...opt,
intent: "danger",
supportingText: "Cannot be selected together with Option A."
};
});
});
const groupSupportingText = computed(() =>
conflict ? "Resolve the option-level errors below." : ""
);
const groupIntent = computed(() => (conflict ? "danger" : "neutral"));vue
<catnip-checklist
label="Choose multiple"
.intent="groupIntent"
.supportingText="groupSupportingText"
.options="options"
.modelValue="selected"
@update:modelValue="selected = $event.detail[0] ?? $event.detail"
/>supportingText on an option accepts a string, string[], or { text, intent?, icon? } (same as Input).
Accessibility
- The group uses
role="group"witharia-labelledbypointing at the field label when visible. - Row
intent="danger"setsaria-invalidon that checkbox’s native input. - Toggling updates
modelValueon the checklist host. - Do not nest
catnip-checkboxinsidecatnip-dropdownoptions — see Checkbox — Guidelines.