VeloxUI
text·free

Count Up

Numbers that count up when scrolled into view, with formatting.

Downloads
Uptime
Rating

Installation

terminal
pnpm add gsap @gsap/react

Then copy the component below into src/components/motion/count-up.tsx. It expects @/lib/gsap (plugin registration) and @/lib/utils (cn).

Source

src/components/motion/count-up.tsx
"use client";

import { useRef } from "react";
import { gsap, useGSAP } from "@/lib/gsap";
import { cn } from "@/lib/utils";

export interface CountUpProps {
  to: number;
  from?: number;
  duration?: number;
  decimals?: number;
  prefix?: string;
  suffix?: string;
  className?: string;
  separator?: string;
}

export function CountUp({
  to,
  from = 0,
  duration = 1.6,
  decimals = 0,
  prefix = "",
  suffix = "",
  separator = ",",
  className,
}: CountUpProps) {
  const ref = useRef<HTMLSpanElement>(null);

  useGSAP(
    () => {
      const el = ref.current;
      if (!el) return;
      const obj = { v: from };
      const fmt = (n: number) => {
        const [i, d] = n.toFixed(decimals).split(".");
        return `${prefix}${i.replace(/\B(?=(\d{3})+(?!\d))/g, separator)}${d ? "." + d : ""}${suffix}`;
      };
      el.textContent = fmt(from);
      gsap.to(obj, {
        v: to,
        duration,
        ease: "power2.out",
        onUpdate: () => (el.textContent = fmt(obj.v)),
        scrollTrigger: { trigger: el, start: "top 90%" },
      });
    },
    { scope: ref, dependencies: [to, from, duration, decimals, prefix, suffix, separator] }
  );

  return <span ref={ref} className={cn("tabular-nums", className)} />;
}