Web InnoventixFreeCode

Big Number Stat

Original · free

big-number highlight stats

byWeb InnoventixReact + Tailwind
statxbignumberstats
Open

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-big-number.json
statx-big-number.tsx
"use client";

import { useEffect, useRef, useState, type KeyboardEvent } from "react";
import {
  motion,
  animate,
  useInView,
  useMotionValue,
  useReducedMotion,
} from "motion/react";

type PeriodId = "quarter" | "launch";

type Stat = {
  key: string;
  label: string;
  prefix?: string;
  suffix?: string;
  value: number;
  decimals: number;
  delta: number;
  deltaSuffix: string;
  good: boolean;
  note: string;
  spark: number[];
};

const PERIODS: { id: PeriodId; label: string }[] = [
  { id: "quarter", label: "This quarter" },
  { id: "launch", label: "Since launch" },
];

const DATA: Record<PeriodId, Stat[]> = {
  quarter: [
    {
      key: "workspaces",
      label: "Active workspaces",
      value: 12480,
      decimals: 0,
      delta: 18.2,
      deltaSuffix: "%",
      good: true,
      note: "Teams shipping on the platform",
      spark: [5, 6, 6, 7, 9, 8, 10, 12, 13],
    },
    {
      key: "latency",
      label: "Median API latency",
      value: 42,
      suffix: " ms",
      decimals: 0,
      delta: -11,
      deltaSuffix: "%",
      good: true,
      note: "p50 measured across every region",
      spark: [58, 55, 53, 50, 49, 47, 45, 43, 42],
    },
    {
      key: "uptime",
      label: "Platform uptime",
      value: 99.98,
      suffix: "%",
      decimals: 2,
      delta: 0.04,
      deltaSuffix: " pts",
      good: true,
      note: "Rolling 90-day availability",
      spark: [99.9, 99.92, 99.95, 99.94, 99.96, 99.97, 99.98],
    },
    {
      key: "throughput",
      label: "Data processed",
      value: 8.6,
      suffix: " PB",
      decimals: 1,
      delta: 23,
      deltaSuffix: "%",
      good: true,
      note: "Events ingested this quarter",
      spark: [4, 4.5, 5.2, 6, 6.4, 7.1, 7.9, 8.6],
    },
  ],
  launch: [
    {
      key: "workspaces",
      label: "Active workspaces",
      value: 41205,
      decimals: 0,
      delta: 214,
      deltaSuffix: "%",
      good: true,
      note: "Cumulative sign-ups since day one",
      spark: [2, 6, 11, 17, 24, 30, 36, 41],
    },
    {
      key: "latency",
      label: "Median API latency",
      value: 38,
      suffix: " ms",
      decimals: 0,
      delta: -34,
      deltaSuffix: "%",
      good: true,
      note: "Down from 58 ms at launch",
      spark: [58, 54, 49, 46, 44, 41, 39, 38],
    },
    {
      key: "uptime",
      label: "Platform uptime",
      value: 99.95,
      suffix: "%",
      decimals: 2,
      delta: 0.12,
      deltaSuffix: " pts",
      good: true,
      note: "Lifetime availability, all regions",
      spark: [99.83, 99.88, 99.9, 99.92, 99.94, 99.95],
    },
    {
      key: "throughput",
      label: "Data processed",
      value: 214,
      suffix: " PB",
      decimals: 0,
      delta: 26,
      deltaSuffix: "x",
      good: true,
      note: "Total events ever ingested",
      spark: [8, 22, 48, 84, 128, 170, 214],
    },
  ],
};

function formatNum(v: number, decimals: number): string {
  return new Intl.NumberFormat("en-US", {
    minimumFractionDigits: decimals,
    maximumFractionDigits: decimals,
  }).format(v);
}

function sparkPath(values: number[], w: number, h: number): string {
  const min = Math.min(...values);
  const max = Math.max(...values);
  const range = max - min || 1;
  const step = values.length > 1 ? w / (values.length - 1) : 0;
  return values
    .map((v, i) => {
      const x = i * step;
      const y = h - ((v - min) / range) * h;
      return `${i === 0 ? "M" : "L"}${x.toFixed(1)},${y.toFixed(1)}`;
    })
    .join(" ");
}

type AnimatedNumberProps = {
  value: number;
  decimals: number;
  active: boolean;
  reduced: boolean;
};

function AnimatedNumber({ value, decimals, active, reduced }: AnimatedNumberProps) {
  const mv = useMotionValue(0);
  const [display, setDisplay] = useState(() => formatNum(0, decimals));

  useEffect(() => {
    const unsub = mv.on("change", (v) => setDisplay(formatNum(v, decimals)));
    return () => unsub();
  }, [mv, decimals]);

  useEffect(() => {
    if (reduced) {
      mv.set(value);
      return;
    }
    if (!active) {
      mv.set(0);
      return;
    }
    const controls = animate(mv, value, {
      duration: 1.3,
      ease: [0.16, 1, 0.3, 1],
    });
    return () => controls.stop();
  }, [value, active, reduced, mv]);

  return <span aria-hidden="true">{display}</span>;
}

function TrendArrow({ up }: { up: boolean }) {
  return (
    <svg
      viewBox="0 0 12 12"
      width="12"
      height="12"
      fill="none"
      aria-hidden="true"
      className={up ? "" : "rotate-180"}
    >
      <path
        d="M6 10V2M6 2L2.5 5.5M6 2l3.5 3.5"
        stroke="currentColor"
        strokeWidth="1.6"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
}

export default function StatxBigNumber() {
  const reduced = useReducedMotion() ?? false;
  const rootRef = useRef<HTMLDivElement>(null);
  const groupRef = useRef<HTMLDivElement>(null);
  const inView = useInView(rootRef, { once: true, amount: 0.3 });
  const [period, setPeriod] = useState<PeriodId>("quarter");

  const stats = DATA[period];
  const activePeriod = PERIODS.find((p) => p.id === period);

  function focusRadio(index: number) {
    const nodes = groupRef.current?.querySelectorAll<HTMLElement>('[role="radio"]');
    nodes?.[index]?.focus();
  }

  function onKeyDown(e: KeyboardEvent<HTMLDivElement>) {
    const len = PERIODS.length;
    const idx = PERIODS.findIndex((p) => p.id === period);
    let next = idx;
    if (e.key === "ArrowRight" || e.key === "ArrowDown") next = (idx + 1) % len;
    else if (e.key === "ArrowLeft" || e.key === "ArrowUp") next = (idx - 1 + len) % len;
    else if (e.key === "Home") next = 0;
    else if (e.key === "End") next = len - 1;
    else return;
    e.preventDefault();
    setPeriod(PERIODS[next].id);
    focusRadio(next);
  }

  return (
    <section className="relative w-full overflow-hidden bg-slate-50 py-20 text-slate-900 sm:py-28 dark:bg-slate-950 dark:text-slate-100">
      <style>{`
        @keyframes statx-pulse {
          0%, 100% { opacity: 1; transform: scale(1); }
          50% { opacity: 0.35; transform: scale(0.72); }
        }
        @keyframes statx-sweep {
          0% { transform: translateX(-120%); }
          100% { transform: translateX(320%); }
        }
        .statx-dot { animation: statx-pulse 2.4s ease-in-out infinite; }
        .statx-sweep { animation: statx-sweep 3.6s ease-in-out infinite; }
        @media (prefers-reduced-motion: reduce) {
          .statx-dot, .statx-sweep { animation: none !important; }
        }
      `}</style>

      {/* atmosphere */}
      <div
        aria-hidden="true"
        className="pointer-events-none absolute inset-0"
      >
        <div className="absolute -top-24 left-1/2 h-80 w-[46rem] -translate-x-1/2 rounded-full bg-indigo-300/25 blur-3xl dark:bg-indigo-600/15" />
        <div className="absolute inset-0 bg-[radial-gradient(circle_at_1px_1px,rgba(148,163,184,0.18)_1px,transparent_0)] [background-size:26px_26px] dark:bg-[radial-gradient(circle_at_1px_1px,rgba(51,65,85,0.30)_1px,transparent_0)]" />
      </div>

      <div ref={rootRef} className="relative mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">
        {/* header */}
        <div className="flex flex-col gap-8 lg:flex-row lg:items-end lg:justify-between">
          <div className="max-w-xl">
            <span className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-white/70 px-3 py-1 text-xs font-medium uppercase tracking-[0.14em] text-slate-600 backdrop-blur dark:border-slate-800 dark:bg-slate-900/70 dark:text-slate-300">
              <span className="relative flex h-2 w-2">
                <span className="statx-dot absolute inline-flex h-2 w-2 rounded-full bg-emerald-500" />
                <span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-500" />
              </span>
              Platform metrics · Live
            </span>
            <h2 className="mt-5 text-balance text-4xl font-semibold tracking-tight sm:text-5xl">
              The numbers behind every deploy
            </h2>
            <p className="mt-4 text-pretty text-base leading-relaxed text-slate-600 dark:text-slate-400">
              A transparent look at how the platform performs for the teams who
              ship on it — drawn straight from production telemetry, not a
              marketing deck.
            </p>
          </div>

          {/* segmented control */}
          <div
            ref={groupRef}
            role="radiogroup"
            aria-label="Select a reporting period"
            onKeyDown={onKeyDown}
            className="inline-flex shrink-0 rounded-full border border-slate-200 bg-slate-100 p-1 dark:border-slate-800 dark:bg-slate-900"
          >
            {PERIODS.map((p) => {
              const selected = p.id === period;
              return (
                <button
                  key={p.id}
                  type="button"
                  role="radio"
                  aria-checked={selected}
                  tabIndex={selected ? 0 : -1}
                  onClick={() => setPeriod(p.id)}
                  className="relative rounded-full px-4 py-2 text-sm font-medium text-slate-600 outline-none transition-colors focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-100 aria-checked:text-slate-900 dark:text-slate-400 dark:focus-visible:ring-offset-slate-900 dark:aria-checked:text-white"
                >
                  {selected && (
                    <motion.span
                      layoutId="statx-pill"
                      aria-hidden="true"
                      transition={
                        reduced
                          ? { duration: 0 }
                          : { type: "spring", stiffness: 420, damping: 34 }
                      }
                      className="absolute inset-0 rounded-full bg-white shadow-sm ring-1 ring-slate-200 dark:bg-slate-700 dark:ring-slate-600"
                    />
                  )}
                  <span className="relative z-10">{p.label}</span>
                </button>
              );
            })}
          </div>
        </div>

        <p className="sr-only" aria-live="polite">
          {`Showing ${activePeriod?.label ?? ""} metrics.`}
        </p>

        {/* grid */}
        <div className="mt-12 grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
          {stats.map((stat, i) => {
            const up = stat.delta >= 0;
            const gradId = `statx-grad-${stat.key}`;
            return (
              <motion.div
                key={stat.key}
                initial={reduced ? false : { opacity: 0, y: 22 }}
                animate={
                  inView || reduced
                    ? { opacity: 1, y: 0 }
                    : { opacity: 0, y: 22 }
                }
                transition={{
                  duration: 0.5,
                  delay: reduced ? 0 : i * 0.08,
                  ease: [0.16, 1, 0.3, 1],
                }}
                className="group relative overflow-hidden rounded-2xl border border-slate-200 bg-white p-6 shadow-sm transition-shadow hover:shadow-md dark:border-slate-800 dark:bg-slate-900/60"
              >
                {/* top accent + shimmer */}
                <div className="pointer-events-none absolute inset-x-0 top-0 h-px overflow-hidden bg-gradient-to-r from-transparent via-indigo-400/70 to-transparent dark:via-indigo-500/60">
                  <span className="statx-sweep absolute inset-y-0 left-0 w-1/3 bg-gradient-to-r from-transparent via-white to-transparent dark:via-indigo-200/80" />
                </div>

                <div className="flex items-start justify-between gap-3">
                  <p className="text-sm font-medium text-slate-500 dark:text-slate-400">
                    {stat.label}
                  </p>
                  <span
                    className={`inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-semibold ${
                      stat.good
                        ? "bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-400"
                        : "bg-rose-100 text-rose-700 dark:bg-rose-500/15 dark:text-rose-400"
                    }`}
                    aria-label={`${up ? "Up" : "Down"} ${Math.abs(stat.delta)}${stat.deltaSuffix}, ${stat.good ? "improved" : "declined"}`}
                  >
                    <TrendArrow up={up} />
                    {`${Math.abs(stat.delta)}${stat.deltaSuffix}`}
                  </span>
                </div>

                <div className="mt-5 flex items-baseline gap-0.5 tracking-tight">
                  {stat.prefix && (
                    <span className="text-2xl font-medium text-slate-400 dark:text-slate-500">
                      {stat.prefix}
                    </span>
                  )}
                  <span className="text-5xl font-semibold tabular-nums text-slate-900 dark:text-white">
                    <AnimatedNumber
                      value={stat.value}
                      decimals={stat.decimals}
                      active={inView}
                      reduced={reduced}
                    />
                  </span>
                  {stat.suffix && (
                    <span className="text-2xl font-medium text-slate-400 dark:text-slate-500">
                      {stat.suffix}
                    </span>
                  )}
                  <span className="sr-only">
                    {`${stat.prefix ?? ""}${formatNum(stat.value, stat.decimals)}${stat.suffix ?? ""}`}
                  </span>
                </div>

                {/* sparkline */}
                <svg
                  viewBox="0 0 120 32"
                  className="mt-4 h-8 w-full"
                  preserveAspectRatio="none"
                  aria-hidden="true"
                >
                  <defs>
                    <linearGradient id={gradId} x1="0" y1="0" x2="1" y2="0">
                      <stop offset="0%" stopColor="rgb(99 102 241)" />
                      <stop offset="100%" stopColor="rgb(139 92 246)" />
                    </linearGradient>
                  </defs>
                  <path
                    d={sparkPath(stat.spark, 120, 32)}
                    fill="none"
                    stroke={`url(#${gradId})`}
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    vectorEffect="non-scaling-stroke"
                  />
                </svg>

                <p className="mt-4 text-sm leading-relaxed text-slate-500 dark:text-slate-400">
                  {stat.note}
                </p>
              </motion.div>
            );
          })}
        </div>

        <p className="mt-8 text-xs text-slate-400 dark:text-slate-500">
          Figures reflect production telemetry aggregated across all regions,
          refreshed every 60 seconds.
        </p>
      </div>
    </section>
  );
}

Dependencies

motion

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 quote

Similar components

Browse all →
Four Stat Metric Band

Four Stat Metric Band

Original

A 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

Labelled Stats With Dividers

Original

Three centred stats separated by responsive dividers, each pairing a headline figure with an uppercase label and supporting detail.

Trusted By Logo Cloud

Trusted By Logo Cloud

Original

A 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

Hero Stat With Supporting Copy

Original

A two-column layout pairing one oversized hero statistic with a supporting paragraph and a checklist card explaining the number.

Count-up stats reveal

Count-up stats reveal

Original

A 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

Animated SVG progress rings

Original

Four 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

Staggered stat band with marquee ticker

Original

A 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

Counter Row Stat

Original

animated counter stats row

Cards Stat

Cards Stat

Original

stat cards with icons

Gradient Stat

Gradient Stat

Original

gradient stats band

Split Stat

Split Stat

Original

stats beside copy

Icons Stat

Icons Stat

Original

icon stat grid