Checkbox Group

Group of related checkboxes backed by an array of selected values. Install Checkbox Group from the VLLNT UI registry with the shadcn CLI.

Report a bug

Group of related checkboxes backed by an array of selected values. Part of the form family in VLLNT UI, it ships as a machine-readable registry entry — copy the source directly into your app with the shadcn CLI and own it, no runtime dependency on a component library.

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Installation

Add Checkbox Group to your project with the shadcn CLI. The source lands in your codebase, ready to adapt:

pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/checkbox-group.json

Source

"use client"; import * as React from "react"; import { cn } from "../../lib/utils"; import { Checkbox } from "../checkbox/checkbox"; import { Label } from "../label/label"; type CheckboxGroupContextValue = { disabled: boolean; name?: string; toggle: (value: string) => void; values: string[]; }; const CheckboxGroupContext = React.createContext<CheckboxGroupContextValue | null>(null); function useCheckboxGroupContext(): CheckboxGroupContextValue { const context = React.use(CheckboxGroupContext); if (!context) { throw new Error("CheckboxGroupItem must be used within a CheckboxGroup"); } return context; } function useCheckboxGroupValue( value: string[] | undefined, defaultValue: string[], onValueChange?: (value: string[]) => void, ) { const [internalValue, setInternalValue] = React.useState(defaultValue); const values = value ?? internalValue; const toggle = React.useCallback( (item: string) => { const nextValues = values.includes(item) ? values.filter((entry) => entry !== item) : [...values, item]; if (value === undefined) { setInternalValue(nextValues); } onValueChange?.(nextValues); }, [onValueChange, value, values], ); return { toggle, values }; } /** Group of related checkboxes backed by an array of selected values. */ export type CheckboxGroupProps = { children: React.ReactNode; className?: string; defaultValue?: string[]; disabled?: boolean; name?: string; onValueChange?: (value: string[]) => void; orientation?: "horizontal" | "vertical"; value?: string[]; }; const CheckboxGroup = ({ children, className, defaultValue = [], disabled = false, name, onValueChange, orientation = "vertical", ref, value, }: CheckboxGroupProps & { ref?: React.Ref<HTMLDivElement> }) => { const { toggle, values } = useCheckboxGroupValue( value, defaultValue, onValueChange, ); const context = React.useMemo<CheckboxGroupContextValue>( () => ({ disabled, name, toggle, values }), [disabled, name, toggle, values], ); return ( <CheckboxGroupContext.Provider value={context}> <div className={cn( "flex gap-3", orientation === "vertical" ? "flex-col" : "flex-row flex-wrap", className, )} ref={ref} role="group" > {children} </div> </CheckboxGroupContext.Provider> ); }; CheckboxGroup.displayName = "CheckboxGroup"; /** Single checkbox plus label wired into the parent CheckboxGroup. */ export type CheckboxGroupItemProps = { children?: React.ReactNode; className?: string; disabled?: boolean; id?: string; value: string; }; const CheckboxGroupItem = ({ children, className, disabled = false, id, ref, value, }: CheckboxGroupItemProps & { ref?: React.Ref<HTMLDivElement> }) => { const generatedId = React.useId(); const itemId = id ?? generatedId; const group = useCheckboxGroupContext(); const checked = group.values.includes(value); return ( <div className={cn("flex items-center gap-2", className)} ref={ref}> <Checkbox checked={checked} disabled={disabled || group.disabled} id={itemId} name={group.name} onCheckedChange={() => { group.toggle(value); }} value={value} /> {children ? <Label htmlFor={itemId}>{children}</Label> : null} </div> ); }; CheckboxGroupItem.displayName = "CheckboxGroupItem"; export { CheckboxGroup, CheckboxGroupItem };

Stories

Explore every variant and state in the interactive Storybook:

Preview

Switch between light and dark to inspect the embedded Storybook preview.

Dependencies

  • @vllnt/ui@^0.3.0