{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "checkbox-group", "title": "Integrated Checkbox Group", "description": "Flat items-driven multi-select CheckboxGroup built on shadcn's base-ui Checkbox: per-option label, description, and disabled, with accessible label/description wiring and class overrides.", "registryDependencies": [ "checkbox" ], "files": [ { "path": "registry/ui/checkbox-group.tsx", "content": "\"use client\";\n\nimport { CheckboxGroup as CheckboxGroupRoot } from \"@base-ui/react/checkbox-group\";\nimport type { ClassValue } from \"clsx\";\nimport { type ReactNode, useId } from \"react\";\nimport { Checkbox } from \"@/components/ui/checkbox\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface CheckboxGroupItem {\n description?: ReactNode;\n descriptionClassName?: ClassValue;\n disabled?: boolean;\n itemClassName?: ClassValue;\n label: ReactNode;\n labelClassName?: ClassValue;\n optionClassName?: ClassValue;\n value: string;\n}\n\nexport interface CheckboxGroupProps\n extends Omit<\n CheckboxGroupRoot.Props,\n \"children\" | \"defaultValue\" | \"onValueChange\" | \"render\" | \"value\"\n > {\n defaultValue?: string[];\n descriptionClassName?: ClassValue;\n itemClassName?: ClassValue;\n items: CheckboxGroupItem[];\n labelClassName?: ClassValue;\n onValueChange?: (\n value: string[],\n eventDetails: CheckboxGroupRoot.ChangeEventDetails\n ) => void;\n optionClassName?: ClassValue;\n value?: string[];\n}\n\nexport const CheckboxGroup = ({\n items,\n optionClassName,\n itemClassName,\n labelClassName,\n descriptionClassName,\n className,\n ...rootProps\n}: CheckboxGroupProps) => {\n const baseId = useId();\n\n return (\n // The base-ui group root is unstyled; bake RadioGroup's layout here so\n // components/ui stays untouched (there is no styled checkbox-group there).\n \n {items.map((item, index) => {\n // Derive ids from the index, not item.value: values may contain\n // whitespace, which would break the space-separated aria-labelledby /\n // aria-describedby token lists and drop the accessible name.\n const labelId = `${baseId}-${index}-label`;\n const descriptionId =\n item.description === undefined\n ? undefined\n : `${baseId}-${index}-description`;\n\n return (\n // biome-ignore lint/a11y/noLabelWithoutControl: the checkbox control is rendered inside.\n \n \n \n \n {item.label}\n \n {item.description !== undefined && (\n \n {item.description}\n \n )}\n \n \n );\n })}\n \n );\n};\n\nexport default CheckboxGroup;\n", "type": "registry:component", "target": "components/easy/checkbox-group.tsx" } ], "type": "registry:component" }