happy travellers
Count-up number
A number that counts up from zero to your figure as soon as it scrolls into view.
Settings
Code
import { useEffect, useRef, useState } from "react";
import { useInView } from "framer-motion";
interface InViewCounterProps {
end?: number;
/** Milisegundos que tarda en llegar a la cifra final. */
duration?: number;
label?: string;
}
export default function InViewCounter({
end = 2400,
duration = 1200,
label = "happy travellers",
}: InViewCounterProps) {
const ref = useRef<HTMLDivElement>(null);
// useInView mira el viewport y respeta el recorte de los contenedores con scroll: funciona en ambos casos.
const seen = useInView(ref, { once: false });
const [n, setN] = useState(0);
useEffect(() => {
if (!seen) {
setN(0);
return;
}
const start = performance.now();
let raf = 0;
const run = (t: number) => {
const p = Math.min(1, (t - start) / duration);
setN(Math.round(end * p));
if (p < 1) raf = requestAnimationFrame(run);
};
raf = requestAnimationFrame(run);
return () => cancelAnimationFrame(raf);
}, [seen, duration, end]);
return (
<div ref={ref} className="text-center text-[#1d1d1f] dark:text-[#f5f5f7]">
<strong className="text-5xl font-semibold tabular-nums">{n.toLocaleString("es-ES")}</strong>
<p className="text-sm text-[#86868b]">{label}</p>
</div>
);
}
Prompt for AI
Paste it into ChatGPT, Claude or Cursor and it will adapt the block to your project with these settings, even if you don’t use React.
More in Text & scroll
Where to use it
Numbers that count up get read, while static ones get skimmed. Use it for the proof section of a landing page: “2,400 happy travelers”, projects delivered by a studio, meals served by a charity or downloads of an app. This animated number counter in React starts when the block becomes visible, not on page load.
Only use figures you can back up, since an animated number draws extra attention to it. Keep the duration around a second; longer and people scroll past before it ends. It counts again every time it comes back into view.