Gradient Stat
Original · freegradient stats band
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/statx-gradient.json"use client";
import {
type KeyboardEvent,
useEffect,
useId,
useRef,
useState,
} from "react";
import { motion, useInView, useReducedMotion } from "motion/react";
type Stat = {
id: string;
label: string;
prefix?: string;
suffix?: string;
value: number;
decimals: number;
delta: string;
trend: "up" | "down";
positive: boolean;
hint: string;
};
type Period = {
id: string;
label: string;
caption: string;
synced: string;
stats: Stat[];
};
const PERIODS: Period[] = [
{
id: "30d",
label: "Last 30 days",
caption: "Rolling window, refreshed every hour",
synced: "Synced 2 minutes ago",
stats: [
{
id: "deploys",
label: "Deploys shipped",
value: 48912,
decimals: 0,
delta: "+12.4%",
trend: "up",
positive: true,
hint: "Across 42 regions, zero-downtime rollouts",
},
{
id: "revenue",
label: "Revenue protected",
prefix: "$",
suffix: "M",
value: 4.2,
decimals: 1,
delta: "+8.1%",
trend: "up",
positive: true,
hint: "Auto-rollback caught it before customers noticed",
},
{
id: "speed",
label: "Median deploy time",
suffix: "s",
value: 38,
decimals: 0,
delta: "-6.0%",
trend: "down",
positive: true,
hint: "p50 from git commit to live production traffic",
},
{
id: "uptime",
label: "Fleet uptime",
suffix: "%",
value: 99.98,
decimals: 2,
delta: "+0.02pt",
trend: "up",
positive: true,
hint: "Measured against a four-nine availability SLA",
},
],
},
{
id: "ytd",
label: "Year to date",
caption: "Jan 1 through today, cumulative",
synced: "Synced 6 minutes ago",
stats: [
{
id: "deploys",
label: "Deploys shipped",
value: 612540,
decimals: 0,
delta: "+34.7%",
trend: "up",
positive: true,
hint: "Across 42 regions, zero-downtime rollouts",
},
{
id: "revenue",
label: "Revenue protected",
prefix: "$",
suffix: "M",
value: 58.6,
decimals: 1,
delta: "+41.2%",
trend: "up",
positive: true,
hint: "Auto-rollback caught it before customers noticed",
},
{
id: "speed",
label: "Median deploy time",
suffix: "s",
value: 41,
decimals: 0,
delta: "-11.0%",
trend: "down",
positive: true,
hint: "p50 from git commit to live production traffic",
},
{
id: "uptime",
label: "Fleet uptime",
suffix: "%",
value: 99.97,
decimals: 2,
delta: "+0.05pt",
trend: "up",
positive: true,
hint: "Measured against a four-nine availability SLA",
},
],
},
{
id: "all",
label: "Since launch",
caption: "All time, from our first production deploy",
synced: "Synced 11 minutes ago",
stats: [
{
id: "deploys",
label: "Deploys shipped",
value: 3184900,
decimals: 0,
delta: "+212%",
trend: "up",
positive: true,
hint: "Across 42 regions, zero-downtime rollouts",
},
{
id: "revenue",
label: "Revenue protected",
prefix: "$",
suffix: "M",
value: 214,
decimals: 1,
delta: "+186%",
trend: "up",
positive: true,
hint: "Auto-rollback caught it before customers noticed",
},
{
id: "speed",
label: "Median deploy time",
suffix: "s",
value: 47,
decimals: 0,
delta: "-3.0%",
trend: "down",
positive: true,
hint: "p50 from git commit to live production traffic",
},
{
id: "uptime",
label: "Fleet uptime",
suffix: "%",
value: 99.95,
decimals: 2,
delta: "4-nine SLA",
trend: "up",
positive: true,
hint: "Measured against a four-nine availability SLA",
},
],
},
];
function TrendArrow({ trend }: { trend: "up" | "down" }) {
return (
<svg
viewBox="0 0 12 12"
width={11}
height={11}
aria-hidden="true"
className={trend === "down" ? "rotate-180" : ""}
>
<path d="M6 2 L10.2 9 L1.8 9 Z" fill="currentColor" />
</svg>
);
}
function CountUp({
target,
decimals,
active,
reduced,
}: {
target: number;
decimals: number;
active: boolean;
reduced: boolean;
}) {
const [display, setDisplay] = useState(reduced ? target : 0);
const displayRef = useRef(display);
displayRef.current = display;
useEffect(() => {
if (reduced) {
setDisplay(target);
return;
}
if (!active) return;
const from = displayRef.current;
const start = performance.now();
const duration = 1200;
let raf = 0;
const tick = (now: number) => {
const t = Math.min(1, (now - start) / duration);
const eased = 1 - Math.pow(1 - t, 3);
setDisplay(from + (target - from) * eased);
if (t < 1) raf = requestAnimationFrame(tick);
};
raf = requestAnimationFrame(tick);
return () => cancelAnimationFrame(raf);
}, [target, active, reduced]);
const formatted = display.toLocaleString("en-US", {
minimumFractionDigits: decimals,
maximumFractionDigits: decimals,
});
return <span className="tabular-nums">{formatted}</span>;
}
export default function StatxGradient() {
const reduced = useReducedMotion() ?? false;
const sectionRef = useRef<HTMLDivElement>(null);
const inView = useInView(sectionRef, { once: true, amount: 0.25 });
const [periodIndex, setPeriodIndex] = useState(0);
const btnRefs = useRef<(HTMLButtonElement | null)[]>([]);
const period = PERIODS[periodIndex];
const headingId = useId();
const groupLabelId = useId();
const captionId = useId();
function handleKey(e: KeyboardEvent<HTMLButtonElement>, i: number) {
const count = PERIODS.length;
let next = i;
if (e.key === "ArrowRight" || e.key === "ArrowDown") next = (i + 1) % count;
else if (e.key === "ArrowLeft" || e.key === "ArrowUp")
next = (i - 1 + count) % count;
else if (e.key === "Home") next = 0;
else if (e.key === "End") next = count - 1;
else return;
e.preventDefault();
setPeriodIndex(next);
btnRefs.current[next]?.focus();
}
return (
<section
aria-labelledby={headingId}
className="relative w-full overflow-hidden bg-slate-50 px-4 py-20 sm:py-28 dark:bg-slate-950"
>
<style>{`
@keyframes statxg-float {
0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
50% { transform: translate3d(0, -18px, 0) scale(1.08); }
}
@keyframes statxg-floatB {
0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
50% { transform: translate3d(16px, 12px, 0) scale(1.06); }
}
@keyframes statxg-sheen {
0% { transform: translateX(-140%) skewX(-12deg); }
55%, 100% { transform: translateX(560%) skewX(-12deg); }
}
@keyframes statxg-pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.35; transform: scale(1.9); }
}
.statxg-blobA { animation: statxg-float 9s ease-in-out infinite; }
.statxg-blobB { animation: statxg-floatB 11s ease-in-out infinite; }
.statxg-sheen { animation: statxg-sheen 7s ease-in-out infinite; }
.statxg-dot { animation: statxg-pulse 2.4s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
.statxg-blobA, .statxg-blobB, .statxg-sheen, .statxg-dot {
animation: none !important;
}
}
`}</style>
<div ref={sectionRef} className="mx-auto max-w-6xl">
<header className="mx-auto max-w-2xl text-center">
<p className="text-sm font-semibold uppercase tracking-[0.2em] bg-gradient-to-r from-indigo-500 via-violet-500 to-sky-500 bg-clip-text text-transparent">
Platform metrics
</p>
<h2
id={headingId}
className="mt-3 text-3xl font-semibold tracking-tight text-slate-900 sm:text-4xl dark:text-white"
>
Numbers that hold up in production
</h2>
<p className="mt-4 text-base leading-relaxed text-slate-600 dark:text-slate-400">
Every figure below comes straight from the control plane, not a
slide deck. Switch the window to see how the fleet performs over
time.
</p>
</header>
<div className="mt-8 flex justify-center">
<div
role="radiogroup"
aria-labelledby={groupLabelId}
className="relative inline-flex items-center gap-1 rounded-full border border-slate-200 bg-slate-100 p-1 dark:border-slate-700 dark:bg-slate-800/70"
>
<span id={groupLabelId} className="sr-only">
Select a reporting period
</span>
{PERIODS.map((p, i) => {
const selected = i === periodIndex;
return (
<button
key={p.id}
ref={(el) => {
btnRefs.current[i] = el;
}}
type="button"
role="radio"
aria-checked={selected}
tabIndex={selected ? 0 : -1}
onClick={() => setPeriodIndex(i)}
onKeyDown={(e) => handleKey(e, i)}
className="relative rounded-full px-4 py-2 text-sm font-medium outline-none transition-colors focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-100 dark:focus-visible:ring-offset-slate-800"
>
{selected && (
<motion.span
layoutId="statxg-pill"
aria-hidden="true"
className="absolute inset-0 rounded-full bg-white shadow-sm dark:bg-slate-950"
transition={
reduced
? { duration: 0 }
: { type: "spring", stiffness: 420, damping: 34 }
}
/>
)}
<span
className={
"relative z-10 " +
(selected
? "text-slate-900 dark:text-white"
: "text-slate-500 dark:text-slate-400")
}
>
{p.label}
</span>
</button>
);
})}
</div>
</div>
<motion.div
initial={reduced ? false : { opacity: 0, y: 26 }}
animate={
reduced
? undefined
: inView
? { opacity: 1, y: 0 }
: { opacity: 0, y: 26 }
}
transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
className="relative mt-10 overflow-hidden rounded-3xl bg-gradient-to-br from-indigo-600 via-violet-600 to-sky-500 p-4 shadow-2xl shadow-indigo-500/25 ring-1 ring-white/10 sm:p-6 dark:from-indigo-800 dark:via-violet-900 dark:to-sky-800 dark:shadow-black/50"
>
<span
aria-hidden="true"
className="statxg-blobA pointer-events-none absolute -left-12 -top-16 h-56 w-56 rounded-full bg-white/25 blur-3xl"
/>
<span
aria-hidden="true"
className="statxg-blobB pointer-events-none absolute -bottom-20 right-0 h-64 w-64 rounded-full bg-sky-300/30 blur-3xl"
/>
<span
aria-hidden="true"
className="statxg-sheen pointer-events-none absolute inset-y-0 left-0 w-1/5 bg-gradient-to-r from-transparent via-white/15 to-transparent"
/>
<div className="relative">
<div className="flex flex-wrap items-center justify-between gap-3 px-2 pb-4 pt-1 sm:px-3">
<span className="inline-flex items-center gap-2 rounded-full bg-white/15 px-3 py-1 text-xs font-semibold text-white ring-1 ring-white/25">
<span className="relative flex h-2 w-2">
<span className="statxg-dot absolute inline-flex h-full w-full rounded-full bg-emerald-300" />
<span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-300" />
</span>
Live control plane
</span>
<span
id={captionId}
aria-live="polite"
className="text-xs font-medium text-white/80"
>
{period.caption}
</span>
</div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 sm:gap-4 lg:grid-cols-4">
{period.stats.map((stat, i) => (
<motion.div
key={stat.id}
initial={reduced ? false : { opacity: 0, y: 16 }}
animate={
reduced
? undefined
: inView
? { opacity: 1, y: 0 }
: { opacity: 0, y: 16 }
}
transition={{
duration: 0.5,
ease: [0.22, 1, 0.36, 1],
delay: reduced ? 0 : 0.12 + i * 0.08,
}}
className="group relative flex flex-col gap-3 rounded-2xl bg-white/10 p-5 ring-1 ring-white/15 backdrop-blur-sm transition-colors hover:bg-white/[0.16] sm:p-6"
>
<div className="flex items-start justify-between gap-3">
<span className="text-sm font-medium text-white/75">
{stat.label}
</span>
<span
className={
"inline-flex shrink-0 items-center gap-1 rounded-full bg-white/15 px-2 py-0.5 text-xs font-semibold ring-1 ring-white/20 " +
(stat.positive
? "text-emerald-100"
: "text-rose-100")
}
>
<span
className={
stat.positive
? "text-emerald-300"
: "text-rose-300"
}
>
<TrendArrow trend={stat.trend} />
</span>
{stat.delta}
</span>
</div>
<div className="text-4xl font-semibold tracking-tight text-white sm:text-[2.75rem] sm:leading-none">
{stat.prefix}
<CountUp
target={stat.value}
decimals={stat.decimals}
active={inView}
reduced={reduced}
/>
{stat.suffix}
</div>
<p className="text-sm leading-relaxed text-white/65">
{stat.hint}
</p>
<span
aria-hidden="true"
className="pointer-events-none absolute inset-x-5 bottom-0 h-px origin-left scale-x-0 bg-gradient-to-r from-white/60 to-transparent transition-transform duration-500 group-hover:scale-x-100"
/>
</motion.div>
))}
</div>
<div className="mt-4 flex flex-wrap items-center justify-between gap-2 px-2 pt-1 text-xs text-white/70 sm:px-3">
<span>{period.synced}</span>
<span className="inline-flex items-center gap-1.5">
<svg
viewBox="0 0 16 16"
width={13}
height={13}
aria-hidden="true"
className="text-white/70"
>
<path
d="M8 1.5 2 4v3.6c0 3.4 2.5 6.1 6 6.9 3.5-.8 6-3.5 6-6.9V4L8 1.5Z"
fill="none"
stroke="currentColor"
strokeWidth={1.3}
strokeLinejoin="round"
/>
<path
d="m5.6 8 1.7 1.7L10.6 6.4"
fill="none"
stroke="currentColor"
strokeWidth={1.3}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
SOC 2 Type II verified figures
</span>
</div>
</div>
</motion.div>
</div>
</section>
);
}Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
Four Stat Metric Band
OriginalA four-column metric band with gradient figures inside a hairline-divided card, ideal for headline numbers like uptime, latency and growth.

Labelled Stats With Dividers
OriginalThree centred stats separated by responsive dividers, each pairing a headline figure with an uppercase label and supporting detail.

Trusted By Logo Cloud
OriginalA responsive six-up logo strip using simple inline-SVG marks and wordmarks with a grayscale-to-colour hover, for a trusted-by section.

Hero Stat With Supporting Copy
OriginalA two-column layout pairing one oversized hero statistic with a supporting paragraph and a checklist card explaining the number.

Count-up stats reveal
OriginalA four-card stat band whose gradient numbers count up from zero as the section scrolls into view, with staggered blur-in cards, a pulsing eyebrow, floating aurora blobs and a shimmering underline sweep.

Animated SVG progress rings
OriginalFour circular SVG progress rings that draw their gradient arcs and count up to their target percentage the moment they enter view, over a slowly rotating conic halo with a soft glow pulse behind each ring.

Staggered stat band with marquee ticker
OriginalA dark stat band where 3D-tilt cards stagger into view with count-up figures over an animated gradient mesh, finished by an infinite marquee ticker of highlight chips that pauses on hover.

Counter Row Stat
Originalanimated counter stats row

Cards Stat
Originalstat cards with icons

Split Stat
Originalstats beside copy
Icons Stat
Originalicon stat grid

Progress Stat
Originalstats with progress rings

