Count Up

A number that counts to its value when it scrolls into view, without a render per frame.

Loading preview

Installation

npx shadcn@latest add @loomui/count-up

No keyframes to add. The count runs on requestAnimationFrame and writes straight to the DOM node.

Usage

import { CountUp } from "@/components/ui/count-up"
<CountUp value={48291} className="text-3xl font-semibold" />
<CountUp value={99.9} decimals={1} suffix="%" />
<CountUp value={12} prefix="$" suffix="M" />

The value is written with textContent rather than through React state. A 1400ms count is one render, not eighty-four. That matters when a stats row has six of these on screen at once.

Numbers are formatted with Intl.NumberFormat, so grouping and decimal separators follow the reader's locale unless you pin one.

Props

PropTypeDefaultDescription
valuenumbernoneThe number to land on.
fromnumber0The number to start from.
durationnumber1400Milliseconds for the whole count.
decimalsnumber0Decimal places held throughout the count.
localestringnonePassed to Intl.NumberFormat.
prefixstringnoneRendered before the number.
suffixstringnoneRendered after the number.
startOnViewbooleantrueWait until the number scrolls into view.
disabledbooleanfalseRender the final value with no count.
classNamestringnoneMerged onto the wrapper. tabular-nums by default.

Any other <span> prop is forwarded to the counting element.

Accessibility

The wrapper carries tabular-nums so digits keep a fixed width and the number does not jitter as it counts. Under prefers-reduced-motion the final value is rendered immediately with no count at all.