{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "checkbox",
  "type": "registry:ui",
  "title": "Checkbox",
  "description": "A binary choice with a precise, legible state.",
  "categories": [
    "inputs"
  ],
  "dependencies": [
    "@radix-ui/react-checkbox",
    "motion"
  ],
  "registryDependencies": [
    "https://mcp.xzero.co.uk/r/xzero-motion-tokens.json"
  ],
  "files": [
    {
      "path": "registry/components/checkbox/checkbox.tsx",
      "type": "registry:component",
      "target": "@components/xzero/checkbox/checkbox.tsx",
      "content": "\"use client\";\n\nimport { forwardRef, useId, useState } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { motion, useReducedMotion } from \"motion/react\";\nimport type { Transition } from \"motion/react\";\nimport { motionTokens } from \"../lib/motion-tokens\";\nimport styles from \"./checkbox.module.css\";\n\nexport interface CheckboxProps extends ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> {\n  label?: string;\n  description?: string;\n}\n\n/** Both marks share three points, so the check morphs into the dash and back instead of swapping. */\nconst checkPath = \"M4.25 9.25 L7.25 12.25 L13.75 5.75\";\nconst dashPath = \"M4.75 9 L9 9 L13.25 9\";\n\nexport const Checkbox = forwardRef<ElementRef<typeof CheckboxPrimitive.Root>, CheckboxProps>(function Checkbox(\n  { label, description, id, className, checked, defaultChecked, onCheckedChange, ...props }, ref,\n) {\n  const generatedId = useId();\n  const controlId = id ?? generatedId;\n  const reduced = useReducedMotion();\n  const [internal, setInternal] = useState<CheckboxPrimitive.CheckedState>(defaultChecked ?? false);\n  const state = checked ?? internal;\n  const on = state !== false;\n  const change = (next: CheckboxPrimitive.CheckedState) => { if (checked === undefined) setInternal(next); onCheckedChange?.(next); };\n  const fade: Transition = { duration: on ? motionTokens.duration.instant : motionTokens.duration.fast, ease: [...motionTokens.ease.standard] };\n  return <div className={styles.field}>\n    <CheckboxPrimitive.Root {...props} id={controlId} ref={ref} checked={state} onCheckedChange={change} className={[styles.box, className].filter(Boolean).join(\" \")} aria-describedby={description ? `${controlId}-description` : undefined} aria-label={props[\"aria-label\"] ?? (label ? undefined : \"Checkbox\")}>\n      <span className={styles.visual} aria-hidden=\"true\">\n        <motion.span className={styles.fill} initial={false} animate={{ opacity: on ? 1 : 0, scale: on ? 1 : .6 }} transition={reduced ? { duration: 0 } : { scale: motionTokens.spring.snappy, opacity: fade }} />\n        <svg className={styles.mark} viewBox=\"0 0 18 18\" fill=\"none\" focusable=\"false\">\n          <motion.path initial={false} animate={{ d: state === \"indeterminate\" ? dashPath : checkPath, pathLength: on ? 1 : 0, opacity: on ? 1 : 0 }} transition={reduced ? { duration: 0 } : { d: motionTokens.spring.morph, pathLength: motionTokens.spring.snappy, opacity: fade }} stroke=\"currentColor\" strokeWidth={1.75} strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n        </svg>\n      </span>\n    </CheckboxPrimitive.Root>\n    {label || description ? <div className={styles.copy}>{label ? <label htmlFor={controlId}>{label}</label> : null}{description ? <span id={`${controlId}-description`}>{description}</span> : null}</div> : null}\n  </div>;\n});\n\nCheckbox.displayName = \"Checkbox\";\n"
    },
    {
      "path": "registry/components/checkbox/checkbox.module.css",
      "type": "registry:component",
      "target": "@components/xzero/checkbox/checkbox.module.css",
      "content": ".field { display: inline-flex; align-items: flex-start; gap: 0; min-width: 0; }\n.box { position: relative; flex: 0 0 auto; display: grid; place-items: center; width: var(--control-height-md); height: var(--control-height-md); border: 0; border-radius: var(--radius-control); padding: 0; background: transparent; color: var(--control-glyph); cursor: pointer; -webkit-tap-highlight-color: transparent; }\n/* The square is the only part that reacts to a press, so the hit area and label never move. */\n.visual { position: relative; display: block; width: 18px; height: 18px; border: 1px solid var(--border-strong); border-radius: 5px; background: var(--surface); transition: border-color var(--duration-fast) var(--ease-standard), transform var(--duration-spring) var(--ease-spring); }\n.fill { position: absolute; inset: -1px; border-radius: inherit; background: var(--control-on); }\n.mark { position: absolute; inset: -1px; width: 18px; height: 18px; overflow: visible; }\n.box[data-state=\"checked\"] .visual, .box[data-state=\"indeterminate\"] .visual { border-color: var(--control-on); }\n@media (hover: hover) and (pointer: fine) { .box[data-state=\"unchecked\"]:hover:not(:disabled) .visual { border-color: var(--text-muted); } }\n.box:active:not(:disabled) .visual { transform: scale(.95); transition: border-color var(--duration-fast) var(--ease-standard), transform var(--duration-instant) var(--ease-standard); }\n.box:disabled { opacity: .5; cursor: not-allowed; }\n/* The label's first line centers on the square: (44px box - 19.6px line) / 2. */\n.copy { display: grid; gap: 2px; min-width: 0; margin-left: 1px; padding-top: calc((var(--control-height-md) - var(--text-sm) * 1.4) / 2); }\n.copy label { color: var(--foreground); font-size: var(--text-sm); font-weight: 500; line-height: var(--leading-body); cursor: pointer; }\n.copy span { color: var(--text-muted); font-size: var(--text-xs); line-height: var(--leading-body); }\n@media (prefers-reduced-motion: reduce) { .visual, .box:active:not(:disabled) .visual { transition: none; transform: none; } }\n"
    }
  ],
  "docs": "Docs and live preview: https://ui.xzero.co.uk/components/checkbox",
  "meta": {
    "tier": "free",
    "kind": "component",
    "tags": [
      "field",
      "form"
    ],
    "docs": "https://ui.xzero.co.uk/components/checkbox",
    "markdown": "https://ui.xzero.co.uk/components/checkbox/markdown"
  }
}