Backgrounds
FreeAnimated Gradient
So a section feels lit rather than painted. Pure CSS, any number of colours.
Install
No key needed.
npx @galactrex/ui add animated-gradientUsage
import { AnimatedGradient } from "@/components/galactrex/animated-gradient";
<section className="relative overflow-hidden">
<AnimatedGradient />
<h1 className="relative">Welcome</h1>
</section>Source
Installs to components/galactrex/animated-gradient.tsx, with the shared motion primitives beside it.
"use client";
import { useRef } from "react";
import { cx } from "@/components/galactrex/motion/cx";
import { useReducedMotion } from "@/components/galactrex/motion/use-reduced-motion";
import { useVisible } from "@/components/galactrex/motion/use-visible";
export type AnimatedGradientProps = {
/** two or more CSS colours; defaults to the background lit by the theme spectrum's blue and violet */
colors?: readonly string[];
/** direction in degrees */
angle?: number;
/** seconds for one pass; the gradient flows there and back */
duration?: number;
/** strength over the parent's own background, 0 to 1 */
opacity?: number;
className?: string;
};
const QUIET = ["var(--gxui-bg)", "var(--gxui-spectrum-2)", "var(--gxui-spectrum-3)", "var(--gxui-bg)"] as const;
/** A linear gradient that drifts slowly across its colours, so a section feels lit rather than painted. Pure CSS.
Place it inside a relative parent, behind content; keep text contrast in mind when you pass bright colours.
Holds still offscreen and with reduced motion. */
export function AnimatedGradient({ colors = QUIET, angle = 120, duration = 14, opacity = 0.5, className }: AnimatedGradientProps) {
const ref = useRef<HTMLDivElement>(null);
const reduced = useReducedMotion();
const visible = useVisible(ref);
const stops = colors.length > 1 ? colors : QUIET;
return (
<div
ref={ref}
aria-hidden
className={cx("pointer-events-none absolute inset-0", className)}
style={{
opacity: Math.min(1, Math.max(0, opacity)),
backgroundImage: `linear-gradient(${angle}deg, ${[...stops, stops[0]].join(", ")})`,
backgroundSize: "300% 300%",
backgroundPosition: "0% 50%",
animation: !reduced && visible && duration > 0 ? `gxui-gradient-flow ${duration}s ease-in-out infinite alternate` : undefined,
}}
/>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
colors | string[] | — | Two or more CSS colours; defaults to quiet theme surfaces. |
angle | number | 120 | Direction in degrees. |
duration | number | 14 | Seconds for one pass, there and back. |
opacity | number | 0.5 | Strength, 0 to 1. |
className | string | — | Extra classes for the outer element. |
Variants
- Quiet. Theme surfaces.
- Brand. Pass `colors` for a brand wash.
Accessibility
- Decorative only and aria-hidden; never takes pointer events.
- Check text contrast when passing bright colours.
Motion and reduced motion
- One CSS background-position animation.
- Still offscreen.
- Reduced motion: a still gradient.