SnippetUI

Stats Counter Card

This is a statistics card component that is ideal for dashboards and landing pages, as the numbers animate and count up from zero as the page scrolls.

HTMLCSSJavaScript

Preview

Four statistics cards are arranged in a grid, and as you scroll, the numbers count up from zero.

🚀
0
Active Users
0%
Satisfaction
🌍
0+
Countries
0%
Uptime

Use cases and features

  • Landing page performance section: Impactfully communicate metrics such as views, customer satisfaction, number of countries, etc.
  • Using Intersection Observer: Animation fires when scrolled and visible for the first time.
  • Decimal point support: Supports both integer and decimal counters with the data-decimals attribute.
  • Color management with CSS variables: You can use the --accent variable to separate accent colors for each card.

Points of design and UX

  1. Ease-out animation: Rather than cubic-bezier, a unique ease-out using a cubic hidden function is a natural movement in which the numerical value stops accelerating.
  2. Gradient text: With -webkit-background-clip: text, the number itself becomes a gradation, creating a premium feel.
  3. Format numbers with toLocaleString(): Display numbers according to the locale, such as 12847 → 12,847.

How to customize

Change counting speed (milliseconds):

// Shorten animation time
// animateCounter(el, target, suffix, decimals, 1000);

// Lengthen animation time
// animateCounter(el, target, suffix, decimals, 3000);

Change decimal places:

<!-- 3 decimal places -->
<span class="stat-number" data-target="99.999" data-suffix="%" data-decimals="3">0%</span>

Implementation code

<div class="stats-grid">
<div class="stat-card stat-card-1">
  <div class="stat-icon">🚀</div>
  <span class="stat-number" data-target="12847" data-suffix="" data-decimals="0">0</span>
  <div class="stat-label">Active Users</div>
</div>
<!-- Similar structure for other cards -->
</div>

<style>
`
.stat-number {
background: linear-gradient(135deg, var(--accent), var(--accent-light));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.stat-card-1 { --accent: #6366f1; --accent-light: #8b5cf6; }
`
</style>

<script>
(function() {
function animateCounter(el, target, suffix, decimals, duration) {
  var start = null;
  function step(ts) {
    if (!start) start = ts;
    var p = Math.min((ts-start)/duration,1);
    var v = (1-Math.pow(1-p,3))*target;
    el.textContent=(decimals>0?v.toFixed(decimals):Math.floor(v).toLocaleString())+suffix;
    if(p<1) requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
}
var observer = new IntersectionObserver(function(entries) {
  entries.forEach(function(e) {
    if (e.isIntersecting) {
      var el = e.target;
      if (!el.classList.contains('animated')) {
        el.classList.add('animated');
        animateCounter(el, parseFloat(el.dataset.target), el.dataset.suffix || '', parseInt(el.dataset.decimals || '0'), 2000);
      }
    }
  });
}, { threshold: 0.5 });

document.querySelectorAll('.stat-number').forEach(function(el) {
  observer.observe(el);
});
})();
</script>

Browser compatibility status

BrowserCompatibility status
Chrome 51+✅ Fully compatible
Firefox 55+✅ Fully compatible
Safari 12.1+✅ Compatible
Edge 79+✅ Fully compatible

The Intersection Observer API supports Nenewa only in modern browsers. A polyfill is required if you want IE11 support.�����������������������������������������