25 CSS Number Counter Animations

5 Pure CSS20 Light JSPublished 10 new designs · Updated on

25 hand-coded CSS number counter animations for SaaS landing-page stat grids, dashboard KPI cards, e-commerce sales tickers, fintech revenue dashboards, healthcare vitals displays, real-estate price meters, gamified level-up widgets, and mission-critical telemetry panels. Each demo is a complete composition — the count-up paired with its chrome: progress bars, SVG ring charts, ticker tapes, odometer flip digits, sparklines, status dots. Ten demos ship Intl.NumberFormat for currency, compact-notation K/M/B, and locale-aware digits; every JS-driven demo gates on IntersectionObserver so counters only fire when scrolled into view. Portable to React (useEffect), Vue (onMounted), Svelte (onMount), and Tailwind v4 @theme keyframes without changing the HTML or CSS. Scoped under .cnc-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.

Related22 CSS Progress Bars18 CSS Scroll Progress Bar22 CSS Countdown Timers30 CSS Keyframe Animations

Course pickPartner: Zero to Mastery

Affiliate link

Want to build production-ready CSS layouts, animations and UI from scratch?

You just browsed 25 counter dashboards. Learn the Flexbox, Grid and animation thinking behind them, so the next component starts in your head, not in a copy-paste.

10% off at checkout with code
Check ZTM Course

Every ZTM course in one membership: $25/month, paid yearly at $299 · 30‑day money-back guarantee

The CSS Bootcamp. We may earn a commission, at no extra cost to you.

01. SaaS Landing Page Key Stats Counter (opens in a new tab)

Published

Pure CSSNEW
The hero stat row every SaaS marketing page ships — 99.98% uptime, 12,480 teams, 4.9 rating — counting up on load with zero JavaScript. A registered @property integer is animated by the style engine and printed as text through counter(), so the numbers are genuinely interpolated rather than swapped between hardcoded strings. Staggered animation-delay gives the row a choreographed cascade instead of four things firing at once.

02. Scroll-Triggered Count Up Statistics Grid (opens in a new tab)

Published

Light JSNEW
Stats that count only when the visitor actually reaches them — the single most-requested counter behaviour on the web. This build ships both routes: a pure-CSS animation-timeline: view() path where the number is literally scrubbed by the scroll position, and an IntersectionObserver fallback that fires the same animation once per card in every other browser. Scroll the panel to watch them run.

03. E-commerce Checkout Live Stock & Sales Counter (opens in a new tab)

Published

Light JSNEW
The scarcity block that lifts checkout conversion without lying to the shopper: a live "only N left" readout that ticks down as other carts claim units, a sold-today counter that climbs, and a stock bar that shifts hue from calm to urgent through a single color-mix() interpolation. Every change is announced politely once, never on every frame.

04. Dashboard KPI Metric Card with Increment Animation (opens in a new tab)

Published

Light JSNEW
The workhorse tile of every admin panel: a headline metric that counts to its new value, a delta chip that flips green or red with a rotating arrow, a CSS-only sparkline, and a live-region announcement when the figure settles. Hover reveals the comparison period. It re-runs on demand so you can watch the increment behaviour that dashboards trigger on every poll.

05. Tailwind CSS Animated Number Counter Badge (opens in a new tab)

Published

Light JSNEW
Notification, cart and inbox badges that pop when the count changes — written twice: once in plain scoped CSS you can paste anywhere, and once as the exact Tailwind v4 utility string (given in the walkthrough) for projects already on Tailwind. The badge scales, the digit rolls, and a 99+ overflow rule keeps the pill from stretching past its design width.

06. User Milestone & Level-Up Progress Counter (opens in a new tab)

Published

Light JSNEW
Duolingo-grade progression in a card: points count up, the XP bar fills past the level threshold, and when it crosses, the level badge flips over with a burst and the bar wraps to the remainder. The reward is the overflow handling — most XP bars break at exactly the moment they matter, when a single action pushes the user past the line.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

07. Live Visitor / Online User Count Widget (opens in a new tab)

Published

Light JSNEW
The "32 people are viewing this right now" widget, built the way a real-time product should build it: a per-digit roll so only the digits that changed move, a breathing live dot, a sparkline of the last 30 seconds, and an aria-live region that speaks at most once every ten seconds no matter how often the socket fires.

08. Pure CSS Odometer Rolling Digit Counter (opens in a new tab)

Published

Pure CSSNEW
A mechanical odometer with no JavaScript at all: six digit columns, each a 0–9 strip translated by its own keyframe animation, with per-column durations in a 10:1 cascade so the units wheel spins ten times faster than the tens — the actual gearing of a physical counter. The blur streak on fast columns and the metal gradient sell the illusion.

09. Currency Formatter Counter with Thousands Separators & K/M/B Suffixes (opens in a new tab)

Published

Light JSNEW
Formatting is where most counters fall apart. This one wraps the tween in Intl.NumberFormat, so the same code renders $1,284,930 in en-US, 1.284.930 $ in de-DE, ₹12,84,930 in the Indian lakh grouping, and a compact $1.28M — correct separators, correct currency placement, correct decimals — while the digits still animate smoothly. Switch locale, currency and notation live.

10. SVG Stroke-Dash Progress Ring Counter (opens in a new tab)

Published

Pure CSSNEW
Three rings, one technique, zero JavaScript: a registered @property drives both the SVG stroke-dashoffset and the printed percentage from the same animation, so the arc and the number can never disagree. A conic-gradient variant and a segmented-track variant are included for comparison.

11. Fundraising Progress & Donation Meter (opens in a new tab)

PublishedUpdated

Light JS
A campaign meter that does the two things donation pages must do: show the raised total climbing toward a goal, and make the next contribution feel consequential. Milestone pips light up as the bar passes them, a live donation feed slides in, and pledging visibly moves the bar — with the goal line, percentage and remaining amount all derived from one number.

12. Retro Flip Odometer & Timer (opens in a new tab)

PublishedUpdated

Light JS
The split-flap board, done properly: each digit is a card split across its horizontal midline, and a change flips the top half down over a pre-rendered next value. The hinge shadow, the card gap and the slight overshoot at the end of the flip are what separate a convincing mechanical display from a rotating rectangle.

13. Product Launch Countdown Timer (opens in a new tab)

PublishedUpdated

Light JS
A launch countdown that survives contact with reality: it computes from a real target timestamp (not a decrementing variable, which drifts and breaks on tab sleep), renders days/hours/minutes/seconds with progress rings, announces at meaningful thresholds only, and degrades to a live 'We're live' state when it reaches zero.

14. Community Growth & User Milestone Counter (opens in a new tab)

PublishedUpdated

Light JS
Social proof that earns its place: an overlapping avatar stack, a member count that climbs with a per-digit roll, a milestone ribbon that fires at each round thousand, and a 7-day growth bar chart drawn in pure CSS grid. Built for the 'Join 50,000+ developers' block that sits above every newsletter form.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

15. ESG Impact & Carbon Footprint Counter (opens in a new tab)

PublishedUpdated

Pure CSS
An impact panel for sustainability reports: tonnes of CO₂ avoided, litres of water saved, trees planted — each counting up in pure CSS, each with its own hand-drawn-feel progress arc, on a calm paper-and-moss palette that deliberately avoids the neon-dashboard look these numbers are usually trapped in.

16. SLA Uptime Percentage Indicator (opens in a new tab)

PublishedUpdated

Pure CSS
The status-page header, rebuilt: 99.982% uptime counting up across four significant digits, a 90-day incident history strip, and an operational badge — all in pure CSS. The interesting problem is decimals, because CSS counters are integers only; the fix is two counters and a literal separator, and it is exact.

17. Blog Reading Time & Scroll Progress Indicator (opens in a new tab)

PublishedUpdated

Light JS
A reading-progress header with a live percentage — and not one line of JavaScript. animation-timeline: scroll() ties both the bar and a counting percentage directly to the scroll position of the article, so the number is scrubbed by the reader's own gesture. Minutes remaining tick down the same way.

18. Real-Time Financial Stock Ticker (opens in a new tab)

PublishedUpdated

Light JS
A trading-desk price list with the two conventions that market UIs live by: a directional flash (green up, red down) that decays in under half a second, and monospaced tabular figures that never shift as prices tick. Includes a scrolling tape marquee, a sparkline per row, and a reduced-motion mode that swaps flashes for static arrows.

19. Fitness Tracker & Daily Step Goal Counter (opens in a new tab)

PublishedUpdated

Light JS
Three concentric activity rings, a step count that rolls as you add movement, and a goal celebration that fires exactly once when the ring closes. The rings are stroked SVG circles sharing one animation clock, so they sweep together like the hardware trackers they reference — and each carries its own accessible progress semantics.

20. Fintech Transaction & Revenue Counter Card (opens in a new tab)

PublishedUpdated

Light JS
A payments card in the language finance products actually use: settled balance counting in, a pending amount underneath, a transaction volume that ticks with each incoming payment, and a stacked 24-hour volume bar. Amounts are integers in minor units end to end — the only way a money counter stays exact.

21. Health Metrics & Heart Rate Animated Display (opens in a new tab)

PublishedUpdated

Light JS
A vitals monitor where the animation itself carries the data: the heart glyph, the ECG sweep and the halo all beat at the patient's actual BPM because their animation-duration is computed from a registered custom property. Change one number and every rhythm in the panel retimes — the classic mistake here is animating at a fixed 1s and letting the visual lie about the reading.

22. Real Estate Price & Square Footage Counter (opens in a new tab)

PublishedUpdated

Light JS
A listing card that counts in the price and the floor area, then derives everything else from them — price per square foot, deposit, monthly repayment — so there is a single source of truth and the derived numbers can never contradict the headline. The down-payment slider recalculates the amortised payment live, which is exactly the interaction that keeps buyers on a listing page.
Newsletter

Enjoying these demos? Get new ones by email.

A short email when a new collection ships. Unsubscribe any time.

at

Almost there: check your inbox to confirm.Manage

23. Gaming Score & XP Points Counter (opens in a new tab)

PublishedUpdated

Light JS
A game HUD built around the problem every score counter hits: points arrive as a stream of overlapping deltas, not as one final value. A naive tween restarts on each hit and silently drops points. This one keeps a persistent target and a single chasing loop, so twenty hits in two seconds all land — with combo multiplier, floating point pops, an XP bar and a level-up flash.

24. B2B SaaS Analytics Summary Grid (opens in a new tab)

PublishedUpdated

Light JS
The summary strip at the top of every B2B analytics product: six metric tiles that re-count whenever the date range changes, each with a delta chip and a sparkline that redraws. One dataset, one render function, one cached formatter per metric — the architecture that stops a dashboard turning into six copies of the same counter code.

25. Mission Telemetry & Countdown Control Panel (opens in a new tab)

PublishedUpdated

Light JS
A launch console: a tenth-of-a-second T-minus clock, live velocity, altitude and downrange readouts, a conic-gradient throttle dial and a flight-event sequencer — every number derived from one authoritative clock. It is the reference implementation for any long-running counter, because the naive version (add 100 ms every 100 ms) drifts by seconds over a flight and looks broken next to a real timer.
FAQ

Frequently asked questions

What is a CSS number counter animation and when should I use one?
A number counter animation is a small interaction where a static figure — revenue, user count, uptime percentage — animates from zero (or another starting value) up to its real value, usually over 1–2.5 seconds with an easing curve. It's the most common motion pattern on SaaS landing pages, dashboard KPI cards, e-commerce sales tickers, fundraising meters, and gamified progress widgets because it gives an otherwise flat number a sense of arrival — drawing the reader's eye exactly where the design wants it. Use it above the fold on marketing pages (Demo 01 SaaS stats grid, Demo 07 live visitor widget), on internal dashboards (Demo 04 KPI card, Demo 24 B2B SaaS analytics), inside e-commerce checkout confirmations (Demo 03 live stock counter), and inside gamified UX (Demo 06 level-up, Demo 23 gaming score). Skip it on utility interfaces where a raw number is faster to read — data-dense tables and admin filter values shouldn't animate.
Do CSS counter animations need JavaScript, or can I do this in pure CSS?
For a true count-up where the digits actually scroll through every intermediate value, you need a small amount of JavaScript — a requestAnimationFrame loop that interpolates a number from 0 to its target with an easing function, writing the rounded value into the element on every frame. CSS alone can animate visual properties (opacity, transform, width, stroke-dashoffset) but cannot drive a textNode through a numeric sequence. Modern CSS @property combined with counter() can build a pure-CSS counter — Demo 08 (Pure CSS Odometer) demonstrates this — but the rendered number tends to be a single typographic style with no easy way to format thousands separators, currency symbols, or locale-aware digits. Every JS demo here is ~15 lines, zero dependencies, and drops into React (useEffect), Vue (onMounted), Svelte (onMount), Astro (island), or vanilla with no changes.
How do I trigger a counter to animate only when it scrolls into view?
Wrap the count-up logic in an IntersectionObserver — Demo 02 (Scroll-Triggered Count Up Statistics Grid) is the reference implementation. Create the observer with a threshold of 0.3 and a rootMargin: '0px 0px -10% 0px', point it at the counter's container, and when the entry intersects, start the requestAnimationFrame loop and disconnect the observer so it does not re-fire when the user scrolls back. This is the right pattern for any counter below the fold — without it, the animation runs while the section is still offscreen and the user arrives at a static final number that has already finished animating. If prefers-reduced-motion is set, skip the observer entirely and set the final value on mount so screen-reader users and motion-sensitive users see the correct number immediately. The observer disconnect is critical: leaked observers accumulate across page navigations and become a memory-leak class Google demotes on repeat interactions.
How do I format currency, thousands separators, and K/M/B suffixes in a counter?
Use Intl.NumberFormat inside the RAF loop instead of raw String(value). Demo 09 (Currency Formatter Counter with Thousands Separators & K/M/B Suffixes) demonstrates the two most common shapes: new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }).format(value) for $1,247,891 output, and a compact-notation form new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }).format(value) for 1.2M / 890K / 4.5B output. Both are locale-aware, so shipping a Japanese, German, or Indian variant means changing the first argument only — no manual comma / thousand-separator handling. The Intl API is fully supported in every current browser (baseline 2019 for currency, 2021 for compact notation). Pair with a tabular-numeric font feature (font-variant-numeric: tabular-nums) on the container so the width doesn't jitter as digits change.
Are these counter animations accessible for screen-reader and reduced-motion users?
Yes. Every demo honors prefers-reduced-motion — when the user has requested less motion at the OS level, the count-up resolves to its final value instantly and the ambient breathing / rotation / pulse animations suppress, so the page is still complete and readable without any transient state. Numbers are rendered as real text in the DOM (not as background images or SVG paths), so screen readers announce the final value correctly. For counters that represent live data — Demo 03 (e-commerce stock), Demo 07 (live visitor widget), Demo 18 (stock ticker) — add aria-live='polite' on the parent so screen readers announce updates without interrupting the user's current focus. Every counter also pairs its number with a visible text label positioned adjacently so the screen-reader announcement reads as "Monthly Recurring Revenue, forty-two thousand dollars" rather than a naked "42000". Focus rings honor :focus-visible, all interactive controls have real <button> semantics, and keyboard-only users can trigger every counter that has a manual replay control.
How do these counters port to React, Vue, Svelte, Angular, or Tailwind?
The JavaScript is framework-agnostic — Demo 05 (Tailwind CSS Animated Number Counter Badge) shows the Tailwind v4 @theme keyframe registration pattern for classes-only styling. For React, wrap the RAF loop in a useEffect(() => { … }, []) that runs once on mount and writes to a ref attached to the number span — the framework's render cycle never re-runs on every animation frame (which would tank INP). For Vue, use onMounted + ref; for Svelte, onMount + bind:this; for Angular, @ViewChild + ngAfterViewInit. In all four the HTML and CSS port unchanged — only the lifecycle hook wrapping the count-up loop changes. Strip the IIFE wrapper from the demo JS, expose the init function, and call it from your framework's mount hook. Compact-notation, currency formatting, IntersectionObserver gating, and reduced-motion checks all remain the same code.
Do animated counters hurt Core Web Vitals or Lighthouse performance scores?
Not if you build them right. requestAnimationFrame yields between frames, so a count-up loop cannot block the main thread for layout, paint, or input responsiveness. Each demo animates a single number (or a small handful in dashboard grids) — well under any performance budget. Two things to watch: writing to textContent triggers a re-layout if the number's character width changes across frames, so wrap the counter in a fixed-width container OR use font-variant-numeric: tabular-nums so every digit occupies the same width; and never count up a number below the fold without an IntersectionObserver gate, because you're spending main-thread frames on something the user cannot see (and Lighthouse penalizes off-screen animation on the Total Blocking Time metric). None of the 25 demos here measurably affect LCP, CLS, or INP in testing on a mid-tier 2024 Android device.

Related collections

20 CSS Animated Buttons preview

20 CSS Animated Buttons

20 hand-coded CSS animated buttons — neon glow, ripple, 3D press, liquid fill, jelly bounce, shine sweep, animated border, moving gradient CTA, text flip, submit success state, add-to-cart progress, download icon, hamburger-to-close, toggle switch, loading spinner inside button, next/prev arrow nav, and ghost button background reveal. Half pure CSS, half lightweight JS for production interactions.

11 CSS animation-timeline Demos preview

11 CSS animation-timeline Demos

11 pure CSS animation-timeline demos built on the W3C scroll() and view() spec — reading progress bar, view-timeline fade & reveal, shrinking sticky header, stacking cards, horizontal scroll section, parallax hero, container shadow indicators, reverse-scroll columns, text scrim reveal, cover card to sticky header, and image zoom / clip-path wipe. Zero JS, off the main thread, Core Web Vitals safe. Copy-paste ready.

25 CSS Background Animations preview

25 CSS Background Animations

25 hand-coded CSS background animations for SaaS hero sections, developer tool documentation, agency portfolios, gaming and Web3 landing pages, seasonal e-commerce campaigns, and dark-mode dashboards. Covers full-screen gradient shifts, animated mesh gradients, aurora borealis glow, cursor spotlight follow, interactive water ripples, dot grid and diagonal stripe patterns, SVG grain and noise texture overlays, topographic contour lines, layered SVG waves, plasma and lava lamp fluids, bokeh light blur, particle constellation networks, matrix digital rain, synthwave 3D perspective grids, starfield warp speed, CRT scanline overlays, fog and mist drift, morphing organic blobs, floating glassmorphism orbs, halftone dot patterns, starry night skies, floating geometric shapes, rising bubbles, and falling snow. 20 are pure CSS with zero JavaScript; the 5 that need it use vanilla canvas or pointer tracking with no dependencies. Every background animates compositor-only properties so it never blocks the main thread, is scoped under a .bga-NN prefix for no-collision pasting, guards prefers-reduced-motion, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.

Search CodeFronts

Loading…