Count-up
A number counts up to its value when it scrolls into view, easing off at the end, and keeps your formatting: currency signs, commas, decimals, % and +.
12,480+teams
98.6%uptime
$4.2Mraised
How to use it
- Paste the snippet just before
</head>. - Put the final number in an element with
data-count-up, written exactly as it should end up, e.g.$1,250.50.
Options
Add any of these attributes to the same element.
data-from | Starting value. Default 0. |
data-duration | Time to count. Default 2000 ms. |
data-loop | Count again every few seconds. |
data-hold | Pause before recounting, when looping. Default 2200 ms. |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/bundles/anime.umd.min.js"></script>
<script>
(function () {
// Count-up: a number counts up to its value when it scrolls into view, keeping
// your formatting: prefixes, suffixes, thousands separators and decimals.
// Usage: <span data-count-up>$1,250.50</span> <span data-count-up>98%</span>
// Optional: data-from (start value, default 0), data-duration (ms), data-loop
// (count again every few seconds), data-hold (ms before recounting).
var DEFAULTS = { duration: 2000, hold: 2200 };
function parse(text) {
var m = text.match(/^(\D*?)(-?[\d,]*\.?\d+)(.*)$/);
if (!m) return null;
var num = m[2];
var decimals = num.indexOf('.') >= 0 ? num.split('.')[1].length : 0;
return { prefix: m[1], suffix: m[3], value: parseFloat(num.replace(/,/g, '')), decimals: decimals, commas: num.indexOf(',') >= 0 };
}
function format(n, f) {
var s = Math.abs(n).toFixed(f.decimals);
if (f.commas) {
var parts = s.split('.');
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
s = parts.join('.');
}
return f.prefix + (n < 0 ? '-' : '') + s + f.suffix;
}
function run(el, f) {
var d = el.dataset;
var state = { n: +d.from || 0 };
el.textContent = format(state.n, f);
anime.animate(state, {
n: f.value,
duration: +d.duration || DEFAULTS.duration,
ease: 'out(4)',
onUpdate: function () { el.textContent = format(state.n, f); },
onComplete: function () {
el.textContent = format(f.value, f);
if (d.loop !== undefined && d.loop !== 'false') setTimeout(function () { run(el, f); }, +d.hold || DEFAULTS.hold);
}
});
}
function init() {
var reduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (!e.isIntersecting) return;
io.unobserve(e.target);
run(e.target, e.target._cu);
});
}, { threshold: 0.5 });
document.querySelectorAll('[data-count-up]').forEach(function (el) {
if (el._cu) return;
var f = parse(el.textContent.trim());
if (!f) return;
el._cu = f;
el.setAttribute('aria-label', el.textContent.trim());
if (reduced) return;
// Hold the final width so the layout doesn't jiggle while counting.
el.style.display = 'inline-block';
el.style.fontVariantNumeric = 'tabular-nums';
el.style.minWidth = el.getBoundingClientRect().width + 'px';
el.textContent = format(+el.dataset.from || 0, f);
io.observe(el);
});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
})();
</script><p><span data-count-up>12,480+</span> teams use it</p>
<p><span data-count-up>98.6%</span> uptime</p>