{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "grid-pattern",
  "title": "Grid Pattern",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A crisp square-grid background in the border color with optional dashed lines, filled cells, softly lighting random cells and an edge fade, drawn as one SVG pattern.",
  "dependencies": [
    "motion@^12"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/grid-pattern.tsx",
      "content": "// Ballmac UI: Grid Pattern. https://ui.ballmac.com/components/grid-pattern\n\"use client\"\n\nimport * as React from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype GridPatternProps = Omit<React.ComponentProps<\"svg\">, \"children\"> & {\n  /** Side of one cell in pixels. */\n  cell?: number\n  /** Horizontal shift of the pattern in pixels. */\n  x?: number\n  /** Vertical shift of the pattern in pixels. */\n  y?: number\n  /** Dash pattern for the lines, such as \"4 3\". \"0\" is solid. */\n  strokeDasharray?: string\n  /** Cells to fill, as [column, row] pairs counted from the top left. */\n  squares?: [number, number][]\n  /** How many extra random cells softly light up and fade. They are picked after mount. */\n  flicker?: number\n  /** Fade the pattern toward the edges. */\n  fade?: \"radial\" | \"top\" | \"bottom\" | \"none\"\n}\n\nconst MASK = {\n  radial: \"radial-gradient(ellipse 70% 70% at 50% 50%, black 25%, transparent 85%)\",\n  top: \"linear-gradient(to bottom, black, transparent 90%)\",\n  bottom: \"linear-gradient(to top, black, transparent 90%)\",\n  none: undefined,\n}\n\n/** A square grid background. Lines and filled cells use the border and foreground tokens. Decorative. */\nfunction GridPattern({ cell = 40, x = -1, y = -1, strokeDasharray = \"0\", squares, flicker = 0, fade = \"radial\", className, style, ...props }: GridPatternProps) {\n  const id = React.useId().replace(/:/g, \"\")\n  const reduce = useReducedMotion()\n  const ref = React.useRef<SVGSVGElement>(null)\n  const [lit, setLit] = React.useState<[number, number][]>([])\n\n  // Random cells are chosen after mount, so the server and browser markup stay identical.\n  React.useEffect(() => {\n    const el = ref.current\n    if (!el || !flicker || reduce) return setLit([])\n    const pick = () => {\n      const cols = Math.max(1, Math.floor(el.clientWidth / cell))\n      const rows = Math.max(1, Math.floor(el.clientHeight / cell))\n      setLit(Array.from({ length: flicker }, () => [Math.floor(Math.random() * cols), Math.floor(Math.random() * rows)] as [number, number]))\n    }\n    pick()\n    const timer = setInterval(pick, 3200)\n    return () => clearInterval(timer)\n  }, [flicker, cell, reduce])\n\n  return (\n    <svg\n      ref={ref}\n      data-slot=\"grid-pattern\"\n      aria-hidden=\"true\"\n      className={cn(\"pointer-events-none absolute inset-0 size-full text-foreground\", className)}\n      style={{ maskImage: MASK[fade], WebkitMaskImage: MASK[fade], ...style }}\n      {...props}\n    >\n      <defs>\n        <pattern id={id} width={cell} height={cell} patternUnits=\"userSpaceOnUse\" x={x} y={y}>\n          <path d={`M${cell} 0 H0 V${cell}`} fill=\"none\" stroke=\"var(--border)\" strokeWidth=\"1\" strokeDasharray={strokeDasharray} />\n        </pattern>\n      </defs>\n      <rect width=\"100%\" height=\"100%\" fill={`url(#${id})`} />\n      {squares?.map(([col, row]) => (\n        <rect key={`s-${col}-${row}`} x={col * cell + x + 1} y={row * cell + y + 1} width={cell - 1} height={cell - 1} fill=\"currentColor\" fillOpacity={0.07} />\n      ))}\n      {lit.map(([col, row], i) => (\n        <motion.rect\n          key={`${col}-${row}-${i}-${lit.length}`}\n          x={col * cell + x + 1}\n          y={row * cell + y + 1}\n          width={cell - 1}\n          height={cell - 1}\n          fill=\"currentColor\"\n          initial={{ fillOpacity: 0 }}\n          animate={{ fillOpacity: [0, 0.1, 0] }}\n          transition={{ duration: 3, delay: i * 0.2, ease: \"easeInOut\" }}\n        />\n      ))}\n    </svg>\n  )\n}\n\nexport { GridPattern, type GridPatternProps }\n",
      "type": "registry:ui",
      "target": "@components/ballmac/grid-pattern.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "grid",
      "pattern",
      "svg",
      "background",
      "lines"
    ],
    "version": "1.0.0",
    "updated": "2026-10-01",
    "ai": {
      "summary": "<GridPattern cell strokeDasharray squares={[[col,row]]} flicker={n} fade='radial|top|bottom|none' /> in a relative parent. Random cells are picked after mount so server and browser agree.",
      "whenToUse": [
        "Section and hero backgrounds that need structure",
        "Behind cards and empty states"
      ],
      "whenNotToUse": [
        "Dots (dot-pattern)",
        "A pointer-reactive grid (interactive-grid)"
      ],
      "composesWith": [
        "dot-pattern",
        "interactive-grid",
        "animated-grid"
      ],
      "a11y": [
        {
          "keys": "Screen readers",
          "action": "Decorative: aria-hidden"
        },
        {
          "keys": "Reduced motion",
          "action": "No random cells light up"
        }
      ],
      "customization": [
        "cell",
        "x and y offset",
        "strokeDasharray",
        "squares",
        "flicker",
        "fade"
      ]
    },
    "examples": [
      "grid-pattern-demo",
      "grid-pattern-variants"
    ],
    "url": "https://ui.ballmac.com/components/grid-pattern"
  },
  "categories": [
    "backgrounds"
  ],
  "type": "registry:ui"
}