shadcn.io is not affiliated with official shadcn/ui
Counting Number counts to its value through every number on the way, like a ticker: it races off, then slows as it closes in, so the last digits tick over one by one before it lands. Give it a new value and it counts on from wherever it is.
Use it for a statistic in a hero, a total on a dashboard, or a figure that grows as people watch. For digits that roll like an odometer, each in its own column, use Sliding Number; for a percentage, Progress Text. A small timer moves the count on every 30 ms and each number is written with Intl.NumberFormat, with no animation library; with reduced motion the value shows at once.
Installation
Usage
import { CountingNumber } from "@/components/ui/counting-number";<CountingNumber value={48215} />Demos
Format
grouping adds thousands separators, and decimals fixes the digits after the point, so 4.8 counts as 0.0, 0.1… rather than in whole numbers. The number is written in locale, en-US by default, so the server and the browser write it alike; pass your own for its separators, as de-DE writes 1.249,90.
Change
Each new value counts on from the number showing, even mid-count, so a total that keeps changing never jumps. from is where the first count starts: here, the total itself, so it only counts the sales. duration is one count, 2000 ms by default; a short one suits a figure that changes often.
From
from can be above the value, and it counts down. trigger="view" holds it at from until it scrolls into view.
Accessibility
Screen readers read the value once, formatted (48,215), from a visually hidden copy, never the numbers on the way; the count itself is hidden from them. It doesn't announce changes by itself: wrap it in a live region (role="status") when a new value should be read out. The figures are tabular, so the number doesn't shift sideways as its digits change.
FAQ
How is it different from Sliding Number?
Counting Number shows every number on the way, written out as text, like a ticker. Sliding Number rolls each digit in its own column straight to its new value, like an odometer, and suits a value that changes by small steps.
Why does it slow down at the end?
The count is eased out: most of the distance goes by in the first moments and the rest slows into the value, so the eye lands on the number rather than chasing it. It never overshoots.
Will the text around it move as it counts?
The digits are tabular, all as wide as each other, so the number only grows when it gains a digit, which happens in the first few moments of a count. For a fixed width from the start, pass pad with the number of digits, which fills the empty places with zeros.
How do I add a currency sign or a unit?
Write it next to the number, as in $<CountingNumber value={128450} /> or <CountingNumber value={42} />%. It stays still while the number counts.
Can it count again?
Give it a new key and React renders it fresh, so it counts again from from. A new value alone counts on from where it is.
API Reference
CountingNumber
<span> data-slot="counting-number"
valuenumber
The number. Each new value counts on from wherever the number is.
decimals?number
How many digits after the decimal point, always shown. @default 0.
- Default
0
duration?number
How long a count takes from start to finish, in milliseconds. @default 2000.
- Default
2000
from?number
Where the first count starts. @default 0.
- Default
0
grouping?boolean
Thousands separators (12,480). @default false.
- Default
false
locale?string
The locale the number is written in (its digits, decimal point and grouping). Fixed by default, so the server and the browser write it the same way.
- Default
"en-US"
onComplete?() → void
Called each time a count reaches its value.
- Returns
void
pad?number
At least this many digits before the decimal point (05). @default 1.
- Default
1
trigger?"mount" | "view"
When the count starts: as soon as the page shows it, or once it scrolls into view.
- Type
"mount" | "view"- Default
"mount"
render?ReactElement | ((props: object, state: object) => ReactElement)
Replace the host element or compose it with another component.
- Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string
Merged with the part's classes.
Related
Sliding Number
NumbersDigits that roll like an odometer
- Pro
Progress Text
NumbersA percentage on rolling reels
- Pro
Countdown Text
NumbersNumbers that run down to a date
- Pro
LCD Text
DecorativeA value in seven segments
- Pro
Rolling Text
CyclingLabels that roll over like a drum
- Pro
Timecode Text
NumbersA counter racing through frames