CountUp.js
~5kb gzippedAnimate numbers with easing and locale-aware formatting.
See It in Action
Each demo animates a different number. Scroll-triggered stats, live currency conversion, and a pricing-plan switcher -- all with the same tiny API.
Four stats counting up when you scroll the block into view. IntersectionObserver triggers CountUp.start() once per stat.
What is CountUp.js?
CountUp.js animates a number from one value to another, with easing and locale-aware formatting. Give it a DOM element, a start, and an end, and it handles the timing, separator placement (1,000 vs 1.000), decimal precision, and prefix/suffix characters ("$" or "%").
It is the default "animated counter" you see on marketing hero sections ("10M+ users") and dashboards. ~5kb gzipped, zero dependencies, an actively maintained API that has been stable for years. Pair it with IntersectionObserver to trigger on scroll-into-view, or with an input listener for a live currency converter.
When to Use CountUp.js
How CountUp.js Compares
Odometer is the classic 'slot-machine' roll-over effect with themed CSS. CountUp is a simpler smooth-counting approach. Pick Odometer when you want the visible digit-by-digit roll; pick CountUp when you want a smooth ease-out to the target.
GSAP can tween any property of an object and you can update DOM text inside onUpdate. More flexible but 40kb larger and more code for the counting case. Use GSAP if you are already using it; pull in CountUp for a standalone counter.
You can write a counter in 10 lines of JS: setInterval + linear increment. CountUp is better because of easing, locale-aware formatting, and correct decimal handling. Small-feature libraries exist to handle the edge cases your hand-rolled version will hit.
Get Started with CountUp.js
npm install countup.js
yarn add countup.js
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/countUp.umd.min.js"></script>
<div id="counter">0</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/countUp.umd.min.js"></script>
<script>
// The UMD global is countUp (lowercase); the class is countUp.CountUp.
const c = new countUp.CountUp("counter", 2450000, {
duration: 2.5,
separator: ",",
prefix: "",
suffix: "+"
});
if (!c.error) {
c.start();
} else {
console.error(c.error);
}
// Later, animate to a new value:
// c.update(3100000);
</script>