{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "blur-fade",
  "title": "Blur Fade",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A wrapper that fades content in while it unblurs and slides a few pixels, once it scrolls into view, with a group that staggers its children.",
  "dependencies": [
    "motion@^12"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/blur-fade.tsx",
      "content": "// Ballmac UI: Blur Fade. https://ui.ballmac.com/components/blur-fade\n\"use client\"\n\nimport * as React from \"react\"\nimport { motion, useInView, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype BlurFadeTag = \"div\" | \"span\" | \"section\" | \"li\" | \"p\" | \"article\" | \"figure\"\n\ntype BlurFadeProps = Omit<React.ComponentProps<\"div\">, \"ref\"> & {\n  /** Seconds to wait before starting. */\n  delay?: number\n  /** Seconds the fade takes. */\n  duration?: number\n  /** Where the content travels from. \"none\" only fades and unblurs. */\n  direction?: \"up\" | \"down\" | \"left\" | \"right\" | \"none\"\n  /** Distance in pixels travelled while fading in. */\n  offset?: number\n  /** Starting blur in pixels. */\n  blur?: number\n  /** Wait until the element scrolls into view before playing. */\n  inView?: boolean\n  /** Play only the first time it enters the view. */\n  once?: boolean\n  /** Element to render. */\n  as?: BlurFadeTag\n}\n\nfunction BlurFade({\n  delay = 0,\n  duration = 0.5,\n  direction = \"up\",\n  offset = 10,\n  blur = 8,\n  inView = true,\n  once = true,\n  as = \"div\",\n  className,\n  children,\n  ...props\n}: BlurFadeProps) {\n  const ref = React.useRef<HTMLElement>(null)\n  const reduce = useReducedMotion()\n  const seen = useInView(ref, { once, margin: \"0px 0px -12% 0px\" })\n  const show = inView ? seen : true\n  const axis = direction === \"left\" || direction === \"right\" ? \"x\" : \"y\"\n  const sign = direction === \"up\" || direction === \"left\" ? 1 : -1\n  const from = direction === \"none\" ? {} : { [axis]: offset * sign }\n  const Tag = motion[as] as typeof motion.div\n\n  return (\n    <Tag\n      ref={ref as React.Ref<HTMLDivElement>}\n      data-slot=\"blur-fade\"\n      initial={false}\n      animate={\n        reduce || show\n          ? { opacity: 1, x: 0, y: 0, filter: \"blur(0px)\" }\n          : { opacity: 0, x: 0, y: 0, ...from, filter: `blur(${blur}px)` }\n      }\n      transition={reduce ? { duration: 0 } : { delay: show ? delay : 0, duration: show ? duration : 0, ease: [0.22, 1, 0.36, 1] }}\n      className={className}\n      {...(props as object)}\n    >\n      {children}\n    </Tag>\n  )\n}\n\ntype BlurFadeGroupProps = Omit<React.ComponentProps<\"div\">, \"ref\"> & {\n  /** Seconds between each child. */\n  stagger?: number\n  /** Seconds before the first child starts. */\n  delay?: number\n  /** Settings passed to every child's BlurFade. */\n  item?: Pick<BlurFadeProps, \"direction\" | \"offset\" | \"blur\" | \"duration\" | \"inView\" | \"once\">\n  /** Element each child is wrapped in. */\n  itemAs?: BlurFadeTag\n}\n\n/** Wraps each child in a BlurFade and staggers them. */\nfunction BlurFadeGroup({ stagger = 0.08, delay = 0, item, itemAs = \"div\", className, children, ...props }: BlurFadeGroupProps) {\n  const items = React.Children.toArray(children)\n  return (\n    <div data-slot=\"blur-fade-group\" className={cn(className)} {...props}>\n      {items.map((child, i) => (\n        <BlurFade key={React.isValidElement(child) && child.key !== null ? child.key : i} as={itemAs} delay={delay + i * stagger} {...item}>\n          {child}\n        </BlurFade>\n      ))}\n    </div>\n  )\n}\n\nexport { BlurFade, BlurFadeGroup, type BlurFadeProps, type BlurFadeGroupProps }\n",
      "type": "registry:ui",
      "target": "@components/ballmac/blur-fade.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "fade",
      "blur",
      "reveal",
      "scroll",
      "stagger"
    ],
    "version": "1.0.0",
    "updated": "2026-10-01",
    "ai": {
      "summary": "Wrap anything in <BlurFade delay direction offset blur inView once>. <BlurFadeGroup stagger> wraps each child and staggers them. Shows content instantly under reduced motion.",
      "whenToUse": [
        "Hero and section intros",
        "Lists and cards that should arrive in sequence"
      ],
      "whenNotToUse": [
        "Text that should animate letter by letter (text-animate)",
        "Content that must be visible without JavaScript before hydration"
      ],
      "composesWith": [
        "text-animate",
        "bento-grid",
        "card"
      ],
      "a11y": [
        {
          "keys": "Reduced motion",
          "action": "Content appears at once with no blur or travel"
        },
        {
          "keys": "Screen readers",
          "action": "Content is in the DOM from the start; only opacity, blur and position change"
        }
      ],
      "customization": [
        "direction: up | down | left | right | none",
        "offset and blur amounts",
        "inView, once, delay, duration",
        "BlurFadeGroup stagger and item settings"
      ]
    },
    "examples": [
      "blur-fade-demo",
      "blur-fade-directions"
    ],
    "url": "https://ui.ballmac.com/components/blur-fade"
  },
  "categories": [
    "motion"
  ],
  "type": "registry:ui"
}