Count-Up Stats
Entry- or scroll-triggered number counters with locale-aware formatting, staggered reveals, synchronized progress visuals, and optional replay.
About This Effect
A stat counter effect that animates numbers from zero to their target on entry or as they scroll into view. Built on GSAP and ScrollTrigger, it preserves locale-aware thousands separators, currency prefixes, percentage suffixes, decimal precision, and one-time scroll behavior through simple data attributes. The JavaScript reads no class names, so the attributes go straight onto whatever stats markup you already have; the demo is an ordinary lead-figure-plus-supporting-metrics band. Optional fills, SVG rings, and a semantic replay control share the same staggered timeline.
What's Included
- Scroll-triggered counting that fires once per stat, never replaying mid-read
- Locale-aware thousands separators via toLocaleString, with custom or disabled separators per counter
- Prefix and suffix support for currency symbols, percentages, and plus signs
- Decimal precision control with GSAP snap so values never show float noise
- Staggered group reveals from a single data-count-stagger attribute on any container
- Card reveals, progress fills, and pathLength-based SVG rings synchronized to each counter
- Optional load trigger and semantic replay control for immediate dashboard sequences
- Custom countup:start and countup:complete events for analytics or chained animations
- Accessible: prefers-reduced-motion users see exact final values immediately, no counting
Perfect For
- SaaS landing page metrics sections with staggered stat cards
- Agency about pages showing projects delivered and client satisfaction
- Annual report or investor pages with revenue and growth figures
- E-commerce social proof strips with download and review counts
- Nonprofit impact dashboards counting donations and people helped
How It Works
Each element with data-count-to gets a proxy counter object animated by gsap.to() with a snap value derived from its decimal precision, so the tween only ever produces valid displayable numbers. An onUpdate callback formats the current value with Intl-backed toLocaleString (or a custom separator) plus any prefix and suffix, while optional fill and SVG ring hooks animate in the same timeline.
A group can start immediately with data-count-trigger="load" or retain the default once-only ScrollTrigger behavior. gsap.matchMedia routes reduced-motion users to exact static values, and the synchronous has-js gate falls back to the final HTML when JavaScript or the GSAP CDN is unavailable.