{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "checkbox",
  "title": "Checkbox",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-vue/components/checkbox/Checkbox.vue",
      "content": "<script setup lang=\"ts\">\nimport type { CheckboxRootProps } from 'reka-ui'\nimport type { ComputedRef, HTMLAttributes } from 'vue'\nimport { computed, getCurrentInstance, inject } from 'vue'\nimport { reactiveOmit } from '@vueuse/core'\nimport { Check, Minus, Loader2 } from 'lucide-vue-next'\nimport { CheckboxIndicator, CheckboxRoot, useForwardPropsEmits } from 'reka-ui'\nimport { cn } from '@/lib/utils'\n\n// CLAUDE.md mandate: `interface Props extends ReakUiX` bails in Vue 3.5+\n// because reka-ui's package.json lacks an `exports.types` condition. The\n// `defineProps<External & Extra>()` intersection delegates type extraction\n// back to the installed TypeScript and is the documented workaround.\nexport type CheckboxProps = Omit<CheckboxRootProps<boolean | string>, 'defaultValue' | 'modelValue'> & {\n  class?: HTMLAttributes['class']\n  /** The controlled checked state of the checkbox. Can be binded with v-model. */\n  modelValue?: boolean | 'indeterminate' | null\n  /** The value given as data when submitted with a name. */\n  value?: string\n  /** Id of the element */\n  id?: string\n  /** The value used when the checkbox is checked. Defaults to `true`. */\n  trueValue?: boolean | string\n  /** The value used when the checkbox is unchecked. Defaults to `false`. */\n  falseValue?: boolean | string\n  /** Size of the checkbox */\n  size?: 'sm' | 'md' | 'lg'\n  /** Custom color for the checked state - matches Vuetify color system */\n  color?: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info' | string\n  /** Label text displayed next to the checkbox */\n  label?: string\n  /** Hint text shown below the checkbox */\n  hint?: string\n  /** Error message to display */\n  errorMessages?: string | string[]\n  /** Whether to show error state */\n  error?: boolean\n  /** When `true`, prevents the user from interacting with the checkbox */\n  disabled?: boolean\n  /** When `true`, the checkbox is in readonly state */\n  readonly?: boolean\n  /** When `true`, shows an indeterminate state */\n  indeterminate?: boolean\n  /** Density of the checkbox - affects spacing */\n  density?: 'compact' | 'default' | 'comfortable'\n  /** When `true`, the icon is hidden */\n  hideIcon?: boolean\n  /** Loading state - shows a spinner */\n  loading?: boolean\n  /** Ripple effect on click */\n  ripple?: boolean\n  /** Custom icon to show when checked */\n  checkedIcon?: any\n  /** Custom icon to show when indeterminate */\n  indeterminateIcon?: any\n  /** Label position - before or after the checkbox */\n  labelPosition?: 'before' | 'after'\n  /** Whether the checkbox appears flat (no elevation) */\n  flat?: boolean\n  /** Whether the checkbox has a background color */\n  bgColor?: boolean\n  /** Inline text style */\n  inline?: boolean\n  /** Name attribute for form submission */\n  name?: string\n}\n\nconst props = withDefaults(defineProps<CheckboxProps>(), {\n  size: 'md',\n  density: 'default',\n  color: 'primary',\n  trueValue: true,\n  falseValue: false,\n  hideIcon: false,\n  ripple: true,\n  labelPosition: 'after',\n  flat: false,\n  bgColor: false,\n  inline: false,\n})\n\nconst emits = defineEmits<{\n  'update:modelValue': [value: boolean | 'indeterminate']\n  change: [value: boolean | 'indeterminate']\n  focus: [event: FocusEvent]\n  blur: [event: FocusEvent]\n}>()\n\nconst delegatedProps = reactiveOmit(\n  props,\n  'class',\n  'size',\n  'color',\n  'label',\n  'hint',\n  'errorMessages',\n  'error',\n  'disabled',\n  'readonly',\n  'indeterminate',\n  'density',\n  'hideIcon',\n  'loading',\n  'ripple',\n  'checkedIcon',\n  'indeterminateIcon',\n  'labelPosition',\n  'flat',\n  'bgColor',\n  'inline',\n  'trueValue',\n  'falseValue',\n  'modelValue',\n  'name',\n)\n\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\n// Injected group context\nconst groupContext = inject<{ name?: ComputedRef<string | undefined> } | null>('checkboxGroupContext', null)\nconst actualName = computed(() => props.name ?? groupContext?.name?.value)\n\n// Size classes\nconst sizeClasses = {\n  sm: 'size-3.5',\n  md: 'size-4',\n  lg: 'size-5',\n}\n\nconst iconSizes = {\n  sm: 'size-2.5',\n  md: 'size-3.5',\n  lg: 'size-4',\n}\n\n// Color classes for checked state\nconst colorClasses: Record<string, string> = {\n  primary:\n    'data-[state=checked]:bg-primary data-[state=checked]:border-primary data-[state=indeterminate]:bg-primary data-[state=indeterminate]:border-primary',\n  secondary:\n    'data-[state=checked]:bg-secondary data-[state=checked]:border-secondary data-[state=indeterminate]:bg-secondary data-[state=indeterminate]:border-secondary',\n  success:\n    'data-[state=checked]:bg-[var(--success)] data-[state=checked]:border-[var(--success)] data-[state=indeterminate]:bg-[var(--success)] data-[state=indeterminate]:border-[var(--success)]',\n  warning:\n    'data-[state=checked]:bg-[var(--warning)] data-[state=checked]:border-[var(--warning)] data-[state=indeterminate]:bg-[var(--warning)] data-[state=indeterminate]:border-[var(--warning)]',\n  error:\n    'data-[state=checked]:bg-destructive data-[state=checked]:border-destructive data-[state=indeterminate]:bg-destructive data-[state=indeterminate]:border-destructive',\n  info: 'data-[state=checked]:bg-[var(--info)] data-[state=checked]:border-[var(--info)] data-[state=indeterminate]:bg-[var(--info)] data-[state=indeterminate]:border-[var(--info)]',\n}\n\n// Density classes\nconst densityClasses = {\n  compact: 'gap-1',\n  default: 'gap-2',\n  comfortable: 'gap-3',\n}\n\n// Build error state\nconst hasError = computed(() => {\n  if (props.error) return true\n  if (\n    props.errorMessages &&\n    (typeof props.errorMessages === 'string' ? props.errorMessages : props.errorMessages.length > 0)\n  )\n    return true\n  return false\n})\n\n// Determine if the checkbox is in an indeterminate state\nconst isIndeterminate = computed(() => {\n  return props.indeterminate || props.modelValue === 'indeterminate'\n})\n\n// Detect whether the parent bound v-model (looks for an onUpdate:modelValue\n// listener) and whether they passed an initial modelValue prop at all (Vue\n// auto-coerces Boolean-union props to `false` when not provided, so a prop\n// check alone can't distinguish controlled vs unbound usage).\nconst instance = getCurrentInstance()\nconst isControlled = computed(() => Boolean(instance?.vnode?.props?.['onUpdate:modelValue']))\nconst userPassedModelValue = computed(() => {\n  const raw = instance?.vnode?.props\n  return Boolean(raw && ('modelValue' in raw || 'model-value' in raw))\n})\n\n// Bind model-value only when actually controlled. Otherwise seed Reka's\n// internal state via default-value so click toggles work.\nconst checkboxStateBindings = computed(() => {\n  if (isIndeterminate.value) return { 'model-value': 'indeterminate' as const }\n  if (isControlled.value) return { 'model-value': props.modelValue }\n  if (userPassedModelValue.value) return { 'default-value': Boolean(props.modelValue) }\n  return { 'default-value': false }\n})\n\n// Build checkbox classes\nconst checkboxClasses = computed(() => {\n  return cn(\n    'peer border-input data-[state=checked]:text-primary-foreground data-[state=indeterminate]:text-primary-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive shrink-0 rounded-[4px] border shadow-xs transition-colors duration-200 outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50',\n    sizeClasses[props.size],\n    colorClasses[props.color] || colorClasses.primary,\n    hasError.value &&\n      'border-destructive data-[state=checked]:!bg-destructive data-[state=checked]:!border-destructive data-[state=indeterminate]:!bg-destructive data-[state=indeterminate]:!border-destructive',\n    props.flat && 'shadow-none',\n    props.class,\n  )\n})\n</script>\n\n<template>\n  <div class=\"flex items-start\" :class=\"[densityClasses[density], inline ? 'inline-flex' : 'flex-col']\">\n    <label\n      v-if=\"label && labelPosition === 'before'\"\n      :for=\"id\"\n      class=\"mr-2 cursor-pointer text-sm leading-none font-medium select-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n      :class=\"[hasError ? 'text-destructive' : '', disabled && 'cursor-not-allowed opacity-50']\"\n    >\n      {{ label }}\n    </label>\n\n    <div class=\"flex items-center\">\n      <CheckboxRoot\n        v-bind=\"{ 'data-slot': 'checkbox', ...forwarded, ...checkboxStateBindings }\"\n        :id=\"id\"\n        v-slot=\"slotProps\"\n        :value=\"value\"\n        :disabled=\"disabled\"\n        :name=\"actualName\"\n        :class=\"checkboxClasses\"\n        @update:model-value=\"(val: boolean | 'indeterminate') => emits('update:modelValue', val)\"\n      >\n        <CheckboxIndicator\n          data-uipkge\n          data-slot=\"checkbox-indicator\"\n          class=\"grid place-content-center text-current transition-none\"\n          :force-mount=\"isIndeterminate || hideIcon\"\n        >\n          <slot v-bind=\"slotProps\">\n            <Loader2 v-if=\"loading\" :class=\"[iconSizes[size], 'animate-spin']\" />\n            <Minus v-else-if=\"isIndeterminate\" :class=\"iconSizes[size]\" />\n            <Check v-else-if=\"!hideIcon\" :class=\"iconSizes[size]\" />\n          </slot>\n        </CheckboxIndicator>\n      </CheckboxRoot>\n\n      <label\n        v-if=\"label && labelPosition === 'after'\"\n        :for=\"id\"\n        class=\"ml-2 cursor-pointer text-sm leading-none font-medium select-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\"\n        :class=\"[hasError ? 'text-destructive' : '', disabled && 'cursor-not-allowed opacity-50']\"\n      >\n        {{ label }}\n      </label>\n    </div>\n\n    <p v-if=\"hint && !hasError\" class=\"text-muted-foreground mt-1 text-xs\">\n      {{ hint }}\n    </p>\n\n    <div v-if=\"hasError\" class=\"mt-1 flex flex-col gap-0.5\">\n      <p v-if=\"typeof errorMessages === 'string'\" class=\"text-destructive text-xs\">\n        {{ errorMessages }}\n      </p>\n      <template v-else>\n        <p v-for=\"(msg, i) in errorMessages\" :key=\"i\" class=\"text-destructive text-xs\">\n          {{ msg }}\n        </p>\n      </template>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/checkbox/Checkbox.vue"
    },
    {
      "path": "packages/registry-vue/components/checkbox/CheckboxGroup.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, provide } from 'vue'\nimport type { ComputedRef, HTMLAttributes } from 'vue'\nimport { reactiveOmit } from '@vueuse/core'\nimport { CheckboxGroupRoot, useForwardProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport Checkbox from './Checkbox.vue'\n\nexport interface CheckboxOption {\n  label: string\n  value: string\n  disabled?: boolean\n}\n\nexport interface CheckboxGroupProps {\n  class?: HTMLAttributes['class']\n  /** The value of the checkbox items that should be checked when initially rendered. */\n  defaultValue?: string[]\n  /** When `true`, prevents the user from interacting with the checkboxes. */\n  disabled?: boolean\n  /** Specifies whether the checkbox group is in an error state */\n  error?: boolean\n  /** Error messages to display */\n  errorMessages?: string | string[]\n  /** Label for the group */\n  label?: string\n  /** Hint text for the group */\n  hint?: string\n  /** The orientation of the checkboxes */\n  orientation?: 'horizontal' | 'vertical'\n  /** Whether to show a border around the group */\n  bordered?: boolean\n  /** Density of the checkboxes */\n  density?: 'compact' | 'default' | 'comfortable'\n  /** Options to render as checkboxes automatically */\n  options?: (string | CheckboxOption)[]\n  /** Name attribute for all checkboxes in the group */\n  name?: string\n  /** Inline layout (alias for horizontal) */\n  inline?: boolean\n}\n\nconst props = withDefaults(defineProps<CheckboxGroupProps>(), {\n  orientation: 'vertical',\n  density: 'default',\n  bordered: false,\n})\n\nconst modelValue = defineModel<string[]>()\n\nconst forwarded = useForwardProps(\n  reactiveOmit(\n    props,\n    'class',\n    'label',\n    'hint',\n    'error',\n    'errorMessages',\n    'density',\n    'bordered',\n    'options',\n    'name',\n    'inline',\n  ),\n)\n\nconst actualOrientation = computed(() => (props.inline ? 'horizontal' : props.orientation))\n\nprovide('checkboxGroupContext', {\n  name: computed(() => props.name),\n})\n</script>\n\n<template>\n  <CheckboxGroupRoot\n    v-bind=\"forwarded\"\n    :model-value=\"modelValue\"\n    @update:model-value=\"modelValue = $event\"\n    :name=\"name\"\n    :orientation=\"actualOrientation\"\n    class=\"flex flex-col gap-2\"\n    :class=\"[\n      actualOrientation === 'horizontal' ? 'flex-row items-center' : 'flex-col',\n      bordered && 'rounded-lg border p-4',\n      props.class,\n    ]\"\n  >\n    <label v-if=\"label\" class=\"text-sm font-medium\">\n      {{ label }}\n    </label>\n\n    <p v-if=\"hint && !error\" class=\"text-muted-foreground text-xs\">\n      {{ hint }}\n    </p>\n\n    <div\n      class=\"flex gap-4\"\n      :class=\"[actualOrientation === 'horizontal' ? 'flex-row flex-wrap items-center' : 'flex-col']\"\n    >\n      <template v-if=\"options && options.length > 0\">\n        <Checkbox\n          v-for=\"(option, i) in options\"\n          :key=\"i\"\n          :value=\"typeof option === 'string' ? option : option.value\"\n          :label=\"typeof option === 'string' ? option : option.label\"\n          :disabled=\"typeof option === 'string' ? undefined : option.disabled\"\n          :name=\"name\"\n          :density=\"density\"\n        />\n      </template>\n\n      <slot v-else :model-value=\"modelValue\" />\n    </div>\n\n    <div v-if=\"error || errorMessages\" class=\"flex flex-col gap-0.5\">\n      <p v-if=\"typeof errorMessages === 'string'\" class=\"text-destructive text-xs\">\n        {{ errorMessages }}\n      </p>\n      <template v-else>\n        <p v-for=\"(msg, i) in errorMessages\" :key=\"i\" class=\"text-destructive text-xs\">\n          {{ msg }}\n        </p>\n      </template>\n    </div>\n  </CheckboxGroupRoot>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/checkbox/CheckboxGroup.vue"
    },
    {
      "path": "packages/registry-vue/components/checkbox/index.ts",
      "content": "export { default as Checkbox } from './Checkbox.vue'\nexport { default as CheckboxGroup } from './CheckboxGroup.vue'\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/checkbox/index.ts"
    }
  ],
  "dependencies": [
    "@vueuse/core",
    "lucide-vue-next",
    "reka-ui"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Standalone or in-form binary toggle, built on reka-ui. Supports indeterminate state for tri-state lists, sizes, and proper keyboard / screen-reader behavior. Pair with Label for clickable text.",
  "categories": [
    "form"
  ]
}