Animated counter
A number that counts to its new value on a wheel of digits, like an odometer.
Loading component source...
Installation
pnpm dlx shadcn@latest add mox/mox-ui/animated-counterRun this command from your project directory to add the component and its dependencies.
- 1
Install the packages
pnpm add motion clsx tailwind-merge - 2
Add the utility file
lib/utils.tsimport { clsx, type ClassValue } from "clsx";import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs));} - 3
Copy and paste the code into your project
Loading source… - 4
Update the import paths to match your project
Point
@/lib/utilsto your utility file if your path aliases differ.
Usage
"use client"
import { AnimatedCounter } from "@/components/ui/animated-counter"
export function Revenue({ total }: { total: number }) { return <AnimatedCounter value={total} className="text-6xl font-medium" />}
// money: two decimals and a currency mark that stays put// <AnimatedCounter value={total} decimals={2} prefix={<span>₹</span>} grouping="indian" />
// fixed width, so a timer never shifts as it rolls over// <AnimatedCounter value={seconds} padStart={4} separator="" />Options
Pick a value to see the prop you would pass. Defaults are left out.
<AnimatedCounter />Props
| Prop | Type | Default | Description |
|---|---|---|---|
value* | number | Default: - | The number to show. Each change animates from whatever is on screen, so it can be updated as often as you like. |
decimals | number | Default: 0 | How many decimal places to keep, up to 15. The value is rounded to that precision, so the wheels always land on a whole digit. |
duration | number | Default: 0.6 | Roughly how many seconds a digit takes to settle on its new face. Lower it when the value updates continuously, so the wheels stay close to the number. |
padStart | number | Default: 1 | Fewest whole digits to show, up to 24, padded with leading zeros. Use it to hold the width steady when the number crosses a power of ten. |
separator | string | Default: "," | Character placed every three whole digits. Pass an empty string to group nothing. |
decimalSeparator | string | Default: "." | Character between the whole and decimal digits. |
grouping | "western" | "indian" | Default: "western" | Where the separators land. Western groups every three digits, 1,234,567. Indian groups the last three then pairs, 12,34,567. |
prefix | ReactNode | Default: - | Rendered before the number, for a currency mark or an icon. It sits outside the wheels and never animates. |
suffix | ReactNode | Default: - | Rendered after the number, for a unit or a percent sign. |
className | string | Default: - | Extra classes merged onto the root element (data-slot="animated-counter"). Size, color, font and weight are all inherited, so style it like text. The digit columns carry data-slot="animated-counter-digit" and the separators data-slot="animated-counter-mark", for reaching either from the root. |
Digits roll up as the number grows and back down as it shrinks, fading in and out at the top and bottom of each window rather than being cut off. A number that keeps changing spins instead of stuttering. The width always matches the number: a place that is gained slides in, one that is lost fades out while the rest close up, and the separators glide along with them.
Credits and license
Most components here are recreations of great work from around the web. I don't claim to be the original creator - this is my attempt to reverse-engineer, replicate, and often add a few extra features. I've tried to credit everyone; if I missed someone, let me know.
- Free to use and modify in both personal and commercial projects.
- Attribution to Mox UI is appreciated when using a component.
- Please don't resell the components as your own kit.