Skip to content
WANCRAFT

G.25Data & Feedback

Animated Counter

A locale-aware count-up number that plays once in view and never shifts the layout.

ReactTailwindbasic

Overview

Animated Counter counts from a start value to its target when it scrolls into view (or on mount). Frames are written directly to the DOM through requestAnimationFrame, so React never re-renders per frame. Formatting goes through Intl.NumberFormat for locale-correct grouping and decimals, an invisible copy of the widest value reserves space so surrounding text stays put, and screen readers always receive the final value rather than a stream of intermediate numbers. When the target changes, the counter animates from the number on screen — never back from zero.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/animated-counter.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/animated-counter.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/animated-counter.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
1 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { AnimatedCounter } from "@/components/ui/animated-counter";

export function AnimatedCounterExample() {
  return (
    <AnimatedCounter
      value={12480}
      className="text-5xl font-semibold tracking-tight"
    />
  );
}

03Props

PropTypeDefaultDescription
valuenumber—Target number. Changing it animates from the value currently on screen.
fromnumber0Start value for the first play.
decimalsnumber0Fixed number of fraction digits.
prefixstring""Text before the number, e.g. a currency symbol.
suffixstring""Text after the number, e.g. % or +.
trigger"view" | "mount""view"Play once when 40% visible, or immediately on mount.
durationnumber2000Animation length in milliseconds.
easing"linear" | "easeOut" | "easeInOut" | "expo""easeOut"Easing curve.
localestring"en-US"BCP 47 locale passed to Intl.NumberFormat.
groupingbooleantrueUse locale grouping separators.
...propsHTMLAttributes<HTMLSpanElement>—Forwarded to the root <span> (className, id, aria-*).

04Features

  • 01Plays once when scrolled into view, or on mount
  • 02Locale-aware formatting via Intl.NumberFormat
  • 03Reserved width and tabular numerals — zero layout shift
  • 04Per-frame updates bypass React rendering
  • 05Retargets smoothly from the on-screen value
motion · tweeninput · viewport

05Accessibility

  • The animated digits are aria-hidden; a visually hidden copy exposes the final formatted value to assistive technology.
  • With prefers-reduced-motion the final value is shown immediately.
  • Renders inline text, so it inherits the surrounding font, size and colour.