✦ A decade of Canvas craft, now driven by AI — describe it, watch it build live.Start building
Bootstrap 5Content

Bootstrap 5 Counter

A Counter component in Bootstrap 5 displays animated numeric statistics that increment from zero to a target value when scrolled into view, drawing attention to key metrics. It typically combines large typographic numbers with short supporting labels, making it ideal for communicating impact at a glance. Use it on landing pages, about pages, or anywhere you need to translate data into a persuasive visual narrative.

Primary Class

.counter

Common Use Cases

  • SaaS product pages showing metrics like '14,000+ active users', 'Uptime 99.9%', or 'Support tickets resolved in under 2 hours'
  • Nonprofit and charity sites displaying fundraising totals, number of people helped, or volunteer hours logged to build donor trust
  • Agency and portfolio pages highlighting completed projects, years of experience, or client satisfaction scores to establish credibility
  • E-commerce stores featuring real-time or cumulative stats such as orders shipped, countries served, or five-star reviews to reduce purchase hesitation

Variants & Classes

VariantDescription
Counter DefaultStandard counter with Bootstrap's default styling.
Counter ResponsiveResponsive variant that adapts to different screen sizes.

Code Example

<section class="py-5 bg-light">
  <div class="container">
    <div class="row text-center g-4">

      <div class="col-6 col-md-3">
        <div class="p-4">
          <h2 class="display-4 fw-bold text-primary counter" data-target="14200">0</h2>
          <p class="text-muted mb-0">Active Users</p>
        </div>
      </div>

      <div class="col-6 col-md-3">
        <div class="p-4">
          <h2 class="display-4 fw-bold text-primary counter" data-target="99">0</h2>
          <p class="text-muted mb-0">% Uptime SLA</p>
        </div>
      </div>

      <div class="col-6 col-md-3">
        <div class="p-4">
          <h2 class="display-4 fw-bold text-primary counter" data-target="380">0</h2>
          <p class="text-muted mb-0">Projects Shipped</p>
        </div>
      </div>

      <div class="col-6 col-md-3">
        <div class="p-4">
          <h2 class="display-4 fw-bold text-primary counter" data-target="4800">0</h2>
          <p class="text-muted mb-0">5-Star Reviews</p>
        </div>
      </div>

    </div>
  </div>
</section>

<script>
  const counters = document.querySelectorAll('.counter');
  const observer = new IntersectionObserver(entries => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const el = entry.target;
        const target = +el.dataset.target;
        const duration = 1800;
        const step = Math.ceil(target / (duration / 16));
        let current = 0;
        const timer = setInterval(() => {
          current = Math.min(current + step, target);
          el.textContent = current.toLocaleString();
          if (current >= target) clearInterval(timer);
        }, 16);
        observer.unobserve(el);
      }
    });
  }, { threshold: 0.4 });
  counters.forEach(c => observer.observe(c));
</script>

Live Examples

Basic Counter

Example 1

Canvas Framework Variants

The Canvas template extends Bootstrap 5 with 1,658+ component variants. Generate any of these using Canvas Builder:

  • Canvas Builder generated counter with custom colours
  • Counter with interactive states
  • Responsive counter for all screen sizes

Best Practices

Use IntersectionObserver, not scroll events

Trigger counter animations only when the section enters the viewport using IntersectionObserver with a threshold of around 0.3–0.5 — this avoids janky scroll listeners and ensures users actually see the animation play out rather than catching it mid-count.

Format large numbers with toLocaleString()

Call Number.toLocaleString() on each incremented value so '14200' renders as '14,200' automatically, adapting to the user's locale — this prevents raw unformatted numbers that look like a bug rather than a statistic.

Pair numbers with icons, not just labels

Adding a Bootstrap Icons icon above each counter (e.g. bi-people-fill for users, bi-star-fill for reviews) gives each stat visual context instantly, reducing cognitive load before the number finishes animating.

Cap animation duration between 1.5s and 2.5s

Animations shorter than 1.5 seconds feel like a flicker on large numbers, while anything over 2.5 seconds loses the viewer's attention — store duration as a data attribute so each counter block can have an individually tuned speed without touching JS.

FAQ

Does Bootstrap 5 include a built-in Counter component?
No — Bootstrap 5 does not ship a counter animation component out of the box. The visual styling (typography scale like display-4, fw-bold, text-primary, grid layout with col-md-3) comes entirely from Bootstrap utilities, while the counting behaviour requires a small vanilla JavaScript snippet using IntersectionObserver. The Canvas HTML template packages this pattern as a ready-made component so you don't have to wire it up manually.
How do I customise the counter colours and font size to match my brand?
Replace text-primary with any Bootstrap colour utility such as text-success, text-warning, or a custom CSS variable like style='color: var(--bs-brand)'. For font size, swap display-4 for display-1 through display-6 depending on hierarchy. If you want per-counter colour variation, add an inline class or a modifier class per column rather than changing the global utility. For CSS-level control, override --bs-primary in your :root block so every text-primary instance updates site-wide.
How does Canvas Builder generate a Counter component?
When you describe a stats section in CanvasBuilder.co — for example, 'show four metrics: users, uptime, projects, and reviews' — the AI outputs a fully structured Counter section using Canvas HTML template markup, with your brand's primary colour applied to the numbers, responsive col-6 col-md-3 grid columns, and the IntersectionObserver animation script already embedded. You get production-ready HTML you can drop straight into your project without writing a single line of JavaScript yourself.