CountUp.js Guide: Animated Number Counter Options & Examples

CountUp.js Guide: Animated Number Counter Options & Examples
CountUp.js is a JavaScript number animation library that counts from one numeric value to another.

It works well for stats sections, dashboard metrics, pricing counters, progress numbers, and scroll-triggered KPI blocks.

The package supports ESM imports, a UMD browser build, TypeScript declarations, custom formatting, callbacks, and animation plugins.

Features

  • Animates numbers from a start value to an end value.
  • Counts up and down based on the target value.
  • Formats decimals, separators, prefixes, and suffixes.
  • Substitutes custom numeral glyphs.
  • Applies smart easing to large values.
  • Starts counters when elements appear on screen.
  • Supports ESM imports and UMD browser scripts.
  • Includes TypeScript declarations.
  • Accepts animation plugins for custom rendering.
  • Cleans up observers and callbacks after teardown.

Use Cases

  • Add animated revenue, user, or download counters to landing pages.
  • Display KPI cards in admin dashboards.
  • Trigger stats animations inside long scrolling pages.
  • Animate pricing, savings, or progress numbers.
  • Format localized numeric counters with custom separators.

How To Use CountUp.js

Install with npm

npm install countup.js

Import CountUp In A Build System

import { CountUp } from 'countup.js';

// Create a counter for the element with id="monthly-revenue".
const revenueCounter = new CountUp('monthly-revenue', 48500, {
  prefix: '$',
  separator: ',',
  duration: 2.4
});

// Start the animation after CountUp validates the target element.
if (!revenueCounter.error) {
  revenueCounter.start();
} else {
  console.error(revenueCounter.error);
}

Use The UMD Browser Build

<div id="active-users">0</div>

<script src="dist/countUp.umd.js"></script>
<script>
  // The UMD build exposes CountUp on the countUp namespace.
  const usersCounter = new countUp.CountUp('active-users', 12750, {
    separator: ',',
    suffix: ' users'
  });

  // Start the counter after the instance passes validation.
  if (!usersCounter.error) {
    usersCounter.start();
  }
</script>

Use A Local ESM File

<div id="orders-counter">0</div>
<script src="./main.js" type="module"></script>
import { CountUp } from './js/countUp.min.js';

window.addEventListener('load', function() {
  // Count from 0 to the final order count.
  const ordersCounter = new CountUp('orders-counter', 3200, {
    separator: ','
  });

  // Start after the page finishes loading.
  ordersCounter.start();
});

Module scripts need a local server in many browsers. A direct file path can trigger a CORS error when the browser loads type="module" scripts from disk.

Count Down From A Custom Start Value

<div id="remaining-seats">120</div>
import { CountUp } from 'countup.js';

// Count down from 120 to 35.
const seatsCounter = new CountUp('remaining-seats', 35, {
  startVal: 120,
  duration: 1.8
});

seatsCounter.start();

Format Currency, Decimals, And Suffixes

<div id="conversion-rate">0</div>
import { CountUp } from 'countup.js';

// Show one decimal place and append a percent sign.
const rateCounter = new CountUp('conversion-rate', 18.7, {
  decimalPlaces: 1,
  decimal: '.',
  suffix: '%',
  duration: 2
});

rateCounter.start();

Start The Counter When It Appears On Screen

<section class="stats-panel">
  <span id="completed-projects">0</span>
</section>
import { CountUp } from 'countup.js';

// autoAnimate starts the counter when the target becomes visible.
const projectCounter = new CountUp('completed-projects', 860, {
  autoAnimate: true,
  autoAnimateDelay: 150,
  autoAnimateOnce: true
});

// Do not call start() when autoAnimate controls the animation.
if (projectCounter.error) {
  console.error(projectCounter.error);
}

autoAnimate uses IntersectionObserver in current releases. Older CountUp.js versions used enableScrollSpy, scrollSpyDelay, and scrollSpyOnce. Those names now exist as deprecated options.

Keep Digits Stable During Animation

.stats-panel span {
  font-variant-numeric: tabular-nums;
}

font-variant-numeric: tabular-nums helps counters look steadier in fonts that use variable-width digits.

Configuration Options

  • startVal (number): Sets the number where the animation begins. Default: 0.
  • decimalPlaces (number): Sets the number of digits after the decimal point. Default: 0.
  • duration (number): Sets the animation length in seconds. Default: 2.
  • useGrouping (boolean): Adds grouping separators to large numbers. Default: true.
  • useIndianSeparators (boolean): Uses Indian-style number grouping. Default: false.
  • useEasing (boolean): Applies easing to the counter animation. Default: true.
  • smartEasingThreshold (number): Sets the value threshold where smart easing begins. Default: 999.
  • smartEasingAmount (number): Sets the eased amount for values above the smart easing threshold. Default: 333.
  • separator (string): Sets the grouping separator character. Default: ','.
  • decimal (string): Sets the decimal character. Default: '.'.
  • easingFn (function): Sets a custom easing function.
  • formattingFn (function): Sets a custom formatter for the rendered value.
  • prefix (string): Adds text before the number. Default: ''.
  • suffix (string): Adds text after the number. Default: ''.
  • numerals (string[]): Replaces the default digits with custom numeral glyphs.
  • onCompleteCallback (function): Runs after the animation completes.
  • onStartCallback (function): Runs when the animation starts.
  • plugin (CountUpPlugin): Uses a custom renderer for alternate animation styles.
  • autoAnimate (boolean): Starts the animation when the target becomes visible. Default: false.
  • autoAnimateDelay (number): Sets the delay in milliseconds after auto animation triggers. Default: 200.
  • autoAnimateOnce (boolean): Runs auto animation only once. Default: false.
  • enableScrollSpy (boolean): Deprecated. Use autoAnimate.
  • scrollSpyDelay (number): Deprecated. Use autoAnimateDelay.
  • scrollSpyOnce (boolean): Deprecated. Use autoAnimateOnce.

API Methods

// Starts the counter animation.
salesCounter.start();

// Starts the animation and runs a callback after completion.
salesCounter.start(function() {
  console.log('Revenue counter finished.');
});

// Pauses the active animation or resumes a paused animation.
salesCounter.pauseResume();

// Resets the counter to its starting value.
salesCounter.reset();

// Updates the end value and animates to the new number.
salesCounter.update(72500);

// Cancels animation work and clears observers and callbacks.
salesCounter.onDestroy();

Events

CountUp.js does not provide a named event system. Use onStartCallback, onCompleteCallback, or the callback argument passed to start() when you need lifecycle hooks.

import { CountUp } from 'countup.js';

const signupCounter = new CountUp('signup-count', 2400, {
  // Runs when the animation starts.
  onStartCallback: function() {
    console.log('Signup counter started.');
  },

  // Runs after the animation completes.
  onCompleteCallback: function() {
    console.log('Signup counter completed.');
  }
});

signupCounter.start();

Plugin Example

CountUp.js supports custom animation plugins. A plugin provides a render() method that receives the target element and the formatted value for each frame.

import { CountUp } from 'countup.js';
import { Odometer } from 'odometer_countup';

// Use the Odometer plugin for a rolling digit effect.
const inventoryCounter = new CountUp('inventory-total', 99999, {
  plugin: new Odometer({
    duration: 2.3,
    lastDigitDelay: 0
  }),
  duration: 3
});

inventoryCounter.start();

Alternatives

FAQs

Q: What is CountUp.js used for?
A: CountUp.js animates numeric values for stats blocks, dashboards, pricing counters, and scroll-triggered KPI sections.

Q: Can CountUp.js count down?
A: Yes. Set a higher startVal and a lower end value.

Q: Does CountUp.js support TypeScript?
A: Yes. The npm package includes TypeScript declaration files.

Q: How do I start CountUp.js when the element appears on screen?
A: Set autoAnimate: true and create the instance. Do not call start() for that counter.

Q: Why does my module import fail from a local HTML file?
A: Browser module scripts often need a local server. Run the page through a local development server.

Q: What replaced enableScrollSpy?
A: Use autoAnimate. Use autoAnimateDelay and autoAnimateOnce for the matching delay and once-only behavior.

Changelog

05/08/2026

  • Rewrite the doc

v2.10.0 (06/02/2025)

  • This release modernizes the “scroll spy” mechanism to use an intersection observer instead of a window on-scroll handler. This also supports triggering animation when the target element becomes visible for other reasons like a modal opening or a parent div becoming visible, so several options have been renamed and old ones deprecated.

v2.9.0 (06/02/2025)

  • Allows getting the endVal from the target element

v2.8.1 (04/23/2025)

  • Provide package.json “exports” for compatibility with modern build systems.

v2.8.0 (08/26/2023)

  • Added onStartCallback option, useful for when scroll spy is enabled

v2.7.0 (06/29/2023)

  • update

v2.6.2 (05/01/2023)

  • bugfix

v2.6.1 (05/01/2023)

  • rebuild

v2.6.0 (03/13/2023)

  • Support animation plugins: A plugin is a class instance or object passed in options for the plugin param that implements a render method.
  • The plugin’s render method will be called on each frame to display the formatted value instead of CountUp’s.

v2.5.0 (03/01/2023)

  • Added new option, onCompleteCallback which gets called when the animation completes. You can still pass a callback to the start method, and it will override whatever is passed in the options.

v2.4.2 (01/29/2023)

  • Make it so when scroll spy is enabled, and scrollSpyOnce is false, CountUp will re-animate when scrolling up, as well as down

v2.4.1 (01/25/2023)

  • Added Indian separators option useIndianSeparators which will format a number like “1,00,000” instead of “100,000”
  • Added null check in printValue method to potentially fix react issue

v2.3.2 (07/10/2022)

  • Fixed a bug where, when using smart easing and counting down, the animation would take longer than configured. It also fixed an issue which caused 2 easing cycles to run for the same scenario.

v2.3.1 (06/29/2022)

  • Fix window check for SSR

v2.3.0 (06/28/2022)

  • Fixes an issue where, when the counter element’s parent is position: relative the scrollSpy function does not trigger when the element scrolls into the view

v2.2.0 (05/18/2022)

  • Added an option to make scroll spy triggered animations run only once

v2.1.0 (03/03/2022)

  • New scroll spy option to trigger animation when the element is scrolled into view.

v2.0.8 (07/28/2020)

  • Add “module” in package.json
  • remove TSLint
  • add ESLint

v2.0.7 (08/26/2020)

  • fixed: Value is not updated correctly when navigating quickly to value

v2.0.6 (08/08/2020)

  • allow certain options to be changed after instantiation
  • UMD module now included

v2.0.4 (06/20/2019)

  • Rewritten in Typescript

v1.9.3 (09/21/2018)

  • Update

The post CountUp.js Guide: Animated Number Counter Options & Examples appeared first on CSS Script.


Discover more from RSS Feeds Cloud

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Discover more from RSS Feeds Cloud

Subscribe now to keep reading and get access to the full archive.

Continue reading