Background Gradient Animation
The "lava lamp" surface: five radial-gradient blobs orbiting behind an SVG goo filter and a 40px blur, over a two-stop gradient backdrop, plus a sixth blob that eases toward the pointer.
Preview
Rendered from the story the storybook (a11y) CI gate runs axe against — the preview can't show something that hasn't been verified.
Install
Two equivalent paths — the URL works in any shadcn-CLI setup; the alias works once you've registered @interlace in your components.json.
npx shadcn@latest add https://ds.interlace.tools/r/background-gradient-animation.jsonnpx shadcn@latest add @interlace/background-gradient-animationHistory
This component is at v1.2.0, first shipped in @interlace/ui 1.0.0. The version is stamped as a banner into the file the install writes, so the copy in your tree says which one you have — compare it with the number above before deciding whether to re-run the install.
No release note names this component yet. It shipped with the release above and has not changed since — see the full changelog for what moved elsewhere in the DS.
Import
2 named exports — pull the parts you need.
import { BackgroundGradientAnimation, GradientBlendMode } from '@/components/ui/aceternity/background-gradient-animation';Anatomy
Extracted from the primitive's JSDoc header. The source is the only documentation that can't drift.
div (data-slot="background-gradient-animation",
isolate, backdrop linear-gradient)
├─ svg.hidden (data-slot="gradient-filter" — feGaussianBlur
│ → feColorMatrix → feBlend, the goo)
├─ div aria-hidden (data-slot="gradient-blobs", filter:url(#<gooId>))
│ ├─ div.animate-first … .animate-fifth
│ └─ div (data-slot="gradient-pointer" — only when active)
└─ div.z-10 (data-slot="gradient-content" — your children)API reference
Parsed from the type declarations in the source — the same file the install writes into your tree, so this table can't drift from the component you get.
BackgroundGradientAnimationProps
| Prop | Type | Description |
|---|---|---|
| gradientBackgroundStart | string | CSS color for the start of the backdrop linear-gradient. Any CSS color is valid; pass a token reference (e.g. `"var(--interlace-accent)"`) to stay on the design system. When omitted, falls back to the brand accent token. @default "var(--interlace-accent)" |
| gradientBackgroundEnd | string | CSS color for the end of the backdrop linear-gradient. Pass a token reference to stay on-brand. When omitted, falls back to the brand primary-active token. @default "var(--interlace-primary-active)" |
| firstColor | string | CSS color of the first (largest, vertically-drifting) blob. When omitted, falls back to the brand primary token. @default "var(--interlace-primary)" |
| secondColor | string | CSS color of the second (counter-rotating) blob. When omitted, falls back to the brand primary-hover token. @default "var(--interlace-primary-hover)" |
| thirdColor | string | CSS color of the third (slow-orbiting) blob. When omitted, falls back to the brand accent-foreground token. @default "var(--interlace-accent-foreground)" |
| fourthColor | string | CSS color of the fourth (horizontally-drifting) blob. When omitted, falls back to the brand primary-subtle-foreground token. @default "var(--interlace-primary-subtle-foreground)" |
| fifthColor | string | CSS color of the fifth (orbiting) blob. When omitted, falls back to the brand secondary-foreground token. @default "var(--interlace-secondary-foreground)" |
| pointerColor | string | CSS color of the pointer-follow blob (only rendered when `interactive`). When omitted, falls back to the brand primary token. @default "var(--interlace-primary)" |
| size | string | Diameter of each blob as a CSS length (relative to the container). Larger values produce a softer, more diffuse wash. @default "80%" |
| blendMode | GradientBlendMode | `mix-blend-mode` applied between the blobs. `hard-light` is the vivid default; `normal` calms the surface. @default "hard-light" |
| interactive | boolean | Render a blob that eases toward the pointer on `pointermove`. Disabled automatically when the user prefers reduced motion. @default true |
| children | ReactNode | Content rendered above the gradient (z-stacked over the decorative layer). The gradient layer is `aria-hidden`, so foreground content keeps its own semantics. |
| contentClassName | string | Class name merged onto the foreground content wrapper. Use it to position or pad your content (the root takes `className` via `...props`). |
Accessibility
Every story for this component is rendered headlessly and checked with axe-core (wcag2aa, wcag22aa, best-practice, ACT) on every PR. That gate has no continue-on-error, so what ships has zero known violations.
What follows is what static analysis can see. Axe cannot press a key and never sees an overlay open, so the operable-without-a-mouse claim lives in Behavior instead, where the keyboard path is replayed step by step.
- Focus + keyboard behaviour
- Native element semantics — no interaction layer to get wrong.
- Focus ring (WCAG 2.2 SC 2.4.13)
- Not focusable — no focus indicator required.
- Reduced motion
- Animation is gated on prefers-reduced-motion.
- ARIA in the source
aria-hidden
Examples
2 more states from the same story file.
Dependencies
- Base UI primitive
- Native / no Base UI dependency
- Lucide icons
- none
- NPM dependencies
- none
- Registry dependencies
Source
The full implementation — components/ui/aceternity/background-gradient-animation.tsx once installed.
"use client";
import {
forwardRef,
useEffect,
useId,
useRef,
type ComponentPropsWithoutRef,
type CSSProperties,
type ReactNode,
} from "react";
// @interlace/background-gradient-animation v1.2.0 — Interlace design system.
// Docs, props and live preview: https://ds.interlace.tools/c/background-gradient-animation
// What changed since: https://ds.interlace.tools/c/background-gradient-animation#history
// Generated banner — keep it, the upgrade diff reads this version.
/**
* @interlace/ui — BackgroundGradientAnimation
*
…356 more lines…Registry JSON
The raw registry record — what the shadcn CLI fetches.