Checkbox Group
Multi-select group of checkboxes sharing a value array. Supports disabled items.
Examples
Controlled multi-select
Several options share one value array; a disabled item is skipped.
Granted: read, write
import { CheckboxGroup, CheckboxGroupItem } from "@codefast/ui/checkbox-group";
import { Label } from "@codefast/ui/label";
import { useState } from "react";
const PERMISSIONS = [
{ value: "read", label: "Read" },
{ value: "write", label: "Write" },
{ value: "delete", label: "Delete" },
{ value: "admin", label: "Admin", disabled: true },
];
export function CheckboxGroupPermissions() {
const [selected, setSelected] = useState<Array<string>>(["read", "write"]);
return (
<div className="space-y-3">
<CheckboxGroup className="gap-3" value={selected} onValueChange={(value) => setSelected(value ?? [])}>
{PERMISSIONS.map(({ value, label, disabled }) => (
<div key={value} className="flex items-center gap-2">
<CheckboxGroupItem id={`perm-${value}`} value={value} {...(disabled ? { disabled } : {})} />
<Label htmlFor={`perm-${value}`} className={disabled ? "opacity-50" : ""}>
{label}
</Label>
</div>
))}
</CheckboxGroup>
<p className="text-xs text-ui-muted">
Granted: <span className="font-medium text-ui-fg">{selected.join(", ") || "none"}</span>
</p>
</div>
);
}
Horizontal layout
Lay items out in a wrapping row.
Working days: Mon, Wed, Fri
import { CheckboxGroup, CheckboxGroupItem } from "@codefast/ui/checkbox-group";
import { Label } from "@codefast/ui/label";
import { useState } from "react";
const DAYS = ["Mon", "Tue", "Wed", "Thu", "Fri"];
export function CheckboxGroupHorizontal() {
const [days, setDays] = useState<Array<string>>(["Mon", "Wed", "Fri"]);
return (
<div className="space-y-3">
<CheckboxGroup className="flex flex-wrap gap-4" value={days} onValueChange={(value) => setDays(value ?? [])}>
{DAYS.map((day) => (
<div key={day} className="flex items-center gap-2">
<CheckboxGroupItem id={`day-${day}`} value={day} />
<Label htmlFor={`day-${day}`}>{day}</Label>
</div>
))}
</CheckboxGroup>
<p className="text-xs text-ui-muted">
Working days: <span className="font-medium text-ui-fg">{days.join(", ") || "none"}</span>
</p>
</div>
);
}
With descriptions
Pair each option with a secondary hint.
When someone replies to your thread.
When you’re @-mentioned anywhere.
A Monday summary of activity.
import { CheckboxGroup, CheckboxGroupItem } from "@codefast/ui/checkbox-group";
import { Label } from "@codefast/ui/label";
import { useState } from "react";
const NOTIFICATIONS = [
{ value: "comments", label: "Comments", hint: "When someone replies to your thread." },
{ value: "mentions", label: "Mentions", hint: "When you’re @-mentioned anywhere." },
{ value: "digest", label: "Weekly digest", hint: "A Monday summary of activity." },
];
export function CheckboxGroupWithDescriptions() {
const [value, setValue] = useState<Array<string>>(["mentions"]);
return (
<CheckboxGroup className="w-full max-w-xs gap-4" value={value} onValueChange={(next) => setValue(next ?? [])}>
{NOTIFICATIONS.map((item) => (
<div key={item.value} className="flex items-start gap-3">
<CheckboxGroupItem id={`notify-${item.value}`} value={item.value} className="mt-0.5" />
<div className="grid gap-0.5">
<Label htmlFor={`notify-${item.value}`}>{item.label}</Label>
<p className="text-xs text-ui-muted">{item.hint}</p>
</div>
</div>
))}
</CheckboxGroup>
);
}
Usage
The minimal import and composition — see Examples below for styled, real-world variants.
import { CheckboxGroup, CheckboxGroupItem } from "@codefast/ui/checkbox-group";
import { Label } from "@codefast/ui/label";
export function CheckboxGroupUsage() {
return (
<CheckboxGroup defaultValue={["mon", "wed"]}>
<div className="flex items-center gap-2">
<CheckboxGroupItem id="mon" value="mon" />
<Label htmlFor="mon">Monday</Label>
</div>
<div className="flex items-center gap-2">
<CheckboxGroupItem id="wed" value="wed" />
<Label htmlFor="wed">Wednesday</Label>
</div>
</CheckboxGroup>
);
}
Anatomy
How the parts nest — every slot the component exposes, in composition order.
Features
- Not built on Radix — a hand-rolled headless primitive, since Radix has no multi-select checkbox-group primitive.
- Shares one value: string[] across every item — checking/unchecking updates array membership, not per-item state.
- Individual items can be disabled while the rest of the group stays interactive.
API reference
Props for each part of the component. All native element props are also forwarded.
CheckboxGroup
A multi-selection group sharing one value array.
valuestring[]The controlled list of checked values.
defaultValuestring[]The checked values when initially rendered (uncontrolled).
onValueChange(value: string[]) => voidCalled when the checked values change.
disabledbooleanDisables the whole group.
Default
false
CheckboxGroupItem
valuestringAdded to the array when checked (required).
disabledbooleanMakes a single item non-selectable.
Default
false
Accessibility
Built to be keyboard-navigable and screen-reader friendly out of the box.
| Key | Function |
|---|---|
| Tab | Moves between checkboxes. |
| Space | Toggles the focused item. |
- Each item is a checkbox with its own aria-checked.
- Pair every item with a Label via matching id / htmlFor.
- Use this over loose checkboxes when they share one value.
Guidelines
Conventions that keep usage consistent across an app.
Do
- Use for choosing several options from a set (permissions, filters).
- Keep a disabled item visible to signal an unavailable option.
Don’t
- Don’t use for one-of-many — use Radio Group.
- Don’t leave items unlabelled.
Explore further
Ready to integrate?
Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.