{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "border-beam",
  "title": "Border Beam",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A short beam of light that travels around the inside edge of its parent's border at a constant speed. Decorative, token-colored, hidden under reduced motion.",
  "dependencies": [
    "motion@^12"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/border-beam.tsx",
      "content": "// Ballmac UI: Border Beam. https://ui.ballmac.com/components/border-beam\n// Based on Magic UI's Border Beam (MIT, Copyright (c) Magic UI), rewritten: span markup, token colors, Motion loop, reduced-motion and support checks.\n\"use client\"\n\nimport * as React from \"react\"\nimport { animate, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype BorderBeamProps = Omit<React.ComponentProps<\"span\">, \"children\"> & {\n  /** Seconds for one lap around the border. */\n  duration?: number\n  /** Seconds before the first lap. Use different delays to offset two beams. */\n  delay?: number\n  /** Length of the beam in pixels. */\n  size?: number\n  /** Color at the head of the beam. Any CSS color. */\n  colorFrom?: string\n  /** Color the beam fades through before its transparent tail. Any CSS color. */\n  colorTo?: string\n  /** Travel counter-clockwise. */\n  reverse?: boolean\n  /** Thickness of the beam in pixels; match your border width. */\n  borderWidth?: number\n}\n\n// Keeps only the border ring: the padding box is cut out of the full box.\nconst borderOnlyMask: React.CSSProperties = {\n  WebkitMask: \"linear-gradient(black, black) padding-box, linear-gradient(black, black)\",\n  WebkitMaskComposite: \"xor\",\n  mask: \"linear-gradient(black, black) padding-box exclude, linear-gradient(black, black)\",\n}\n\nfunction BorderBeam({\n  duration = 8,\n  delay = 0,\n  size = 80,\n  colorFrom = \"var(--ring)\",\n  colorTo = \"color-mix(in oklch, var(--ring) 45%, transparent)\",\n  reverse = false,\n  borderWidth = 1,\n  className,\n  style,\n  ...props\n}: BorderBeamProps) {\n  const beamRef = React.useRef<HTMLSpanElement>(null)\n  const reduceMotion = useReducedMotion()\n\n  React.useEffect(() => {\n    const beam = beamRef.current\n    if (!beam || reduceMotion) return\n    // Browsers without offset-path rect() would park the beam in a corner; hide it instead.\n    if (typeof CSS !== \"undefined\" && !CSS.supports(\"offset-path\", \"rect(0 auto auto 0)\")) {\n      beam.style.display = \"none\"\n      return\n    }\n    const controls = animate(\n      beam,\n      { offsetDistance: reverse ? [\"100%\", \"0%\"] : [\"0%\", \"100%\"] },\n      { duration, delay, ease: \"linear\", repeat: Infinity }\n    )\n    return () => controls.stop()\n  }, [duration, delay, reverse, reduceMotion])\n\n  return (\n    <span\n      aria-hidden=\"true\"\n      data-slot=\"border-beam\"\n      className={cn(\n        \"pointer-events-none absolute inset-0 block overflow-hidden rounded-[inherit] border-solid border-transparent motion-reduce:hidden\",\n        className\n      )}\n      style={{ ...borderOnlyMask, borderWidth, ...style }}\n    >\n      <span\n        ref={beamRef}\n        data-slot=\"border-beam-light\"\n        className=\"absolute block aspect-square\"\n        style={{\n          width: size,\n          offsetPath: `rect(0 auto auto 0 round ${size}px)`,\n          offsetDistance: \"0%\",\n          // The head of the beam faces the direction of travel.\n          background: `linear-gradient(${reverse ? \"to right\" : \"to left\"}, ${colorFrom}, ${colorTo}, transparent)`,\n        }}\n      />\n    </span>\n  )\n}\n\nexport { BorderBeam, type BorderBeamProps }\n",
      "type": "registry:ui",
      "target": "@components/ballmac/border-beam.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "border",
      "glow",
      "highlight",
      "decorative",
      "motion"
    ],
    "version": "1.0.0",
    "updated": "2026-09-28",
    "ai": {
      "summary": "Drop <BorderBeam /> as the last child of any element with position: relative and a border radius; it inherits the radius and draws only in a borderWidth-thick ring (aria-hidden, pointer-events-none). Renders a span, so it is valid inside buttons.",
      "whenToUse": [
        "Drawing attention to one highlighted card, such as the recommended pricing plan",
        "Marking a live or running state on a panel (an agent working, a deploy in progress)",
        "A featured call-to-action button"
      ],
      "whenNotToUse": [
        "Several elements on the same screen; one beam per view",
        "Communicating status on its own (pair it with text; it is hidden under reduced motion)"
      ],
      "composesWith": [
        "spotlight-card",
        "button",
        "magnetic-button"
      ],
      "a11y": [],
      "customization": [
        "duration (s per lap, default 8), delay, reverse",
        "size: beam length in px (default 80); borderWidth: ring thickness in px (default 1)",
        "colorFrom / colorTo: any CSS color, default var(--ring) fading out; try var(--chart-2)",
        "Two beams with delay={duration / 2} give an opposed pair; className=\"-inset-px\" moves the ring onto a 1px parent border",
        "Needs CSS offset-path rect() (Chrome 116, Firefox 122, Safari 17.2); older browsers simply don't show the beam"
      ]
    },
    "source": {
      "name": "Magic UI Border Beam",
      "url": "https://github.com/magicuidesign/magicui",
      "license": "MIT",
      "copyright": "Copyright (c) Magic UI",
      "modified": true
    },
    "examples": [
      "border-beam-demo",
      "border-beam-button"
    ],
    "url": "https://ui.ballmac.com/components/border-beam"
  },
  "categories": [
    "motion"
  ],
  "type": "registry:ui"
}