Animated Number
A number display that tweens from its previous value to a new one on every change — the dashboard stat-card counter.
- Status
- Since
0.1.0- Accessibility pattern
- decorative text (aria-hidden)
Last updated
Install
Add Animated Number from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.
pnpm dlx shadcn@latest add @vegastack/animated-numberThe same command installs the registry items it composes: @vegastack/use-media-query.
Usage
import { AnimatedNumber } from "@/components/ui/animated-number";
<AnimatedNumber value={revenue} />;Renders the exact value statically on mount — no count-up flash, no hydration mismatch. Every
LATER value change tweens the displayed number from whatever is currently shown to the new
value, over the duration motion token.
Examples
Currency and compact formats
format takes full Intl.NumberFormatOptions — currency, percent, compact notation, custom
grouping. Every intermediate frame of the tween is formatted through the same
Intl.NumberFormat(locale, format) instance as the settled value, so the $ symbol, cent
grouping, or compact suffix ("12.4K") stay correct throughout the animation, not just at rest.
Duration
duration is a motion-token name ('fast' | 'base' | 'slow', default 'base') — resolved from
the live --duration-fast/base/slow CSS custom property at animation start, never a hardcoded
millisecond value. Easing reads --motion-ease-standard the same way. Overriding either token at
runtime (e.g. scoping --duration-base on a container) retunes the tween without a prop.
Interruption
Changing value again before a tween finishes retargets it smoothly from wherever the number
currently sits — it never snaps back to an earlier value first.
// Rapid updates (e.g. a live ticker) each interrupt the last, always converging on
// the LATEST value with one continuous motion, not a stutter per update.
<AnimatedNumber
value={livePrice}
format={{ style: "currency", currency: "USD" }}
/>Playground
Pick a different value preset to watch the tween, try the format and duration options, then copy the generated JSX.
<AnimatedNumber value={1204} />API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
value* | number | — | The number to display. On mount it renders statically (no animation). On every later change, the displayed value tweens from whatever is currently shown to this new value. Changing it again mid-tween interrupts the current animation and retargets from the in-flight value — it never snaps back to an earlier value first. |
duration | "base" | "fast" | "slow" | 'base' | Tween duration, as a motion-token name (never a raw millisecond value) — resolved from the
live --duration-{fast,base,slow} CSS custom property at animation start. |
format | Intl.NumberFormatOptions | — | Intl.NumberFormatOptions used to format both the settled value and every animated
intermediate frame — e.g. { style: 'currency', currency: 'USD' } or
{ notation: 'compact' }. Omit for plain locale-grouped digits. |
locale | string | string[] | — | BCP-47 locale(s) for Intl.NumberFormat. Defaults to the runtime locale. |
Data attributes and CSS variables on AnimatedNumber
| Attribute | Values |
|---|---|
data-slot | "animated-number" | "animated-number-live" | "animated-number-value" |
Accessibility
- The ticking visual text is
aria-hidden— a rapid stream of announcements while a number climbs would be noise, not useful information. - A visually-hidden
role="status"/aria-live="polite"region announces only the settled value, once per tween completion — never the intermediate frames. prefers-reduced-motion: reducerenders every value change instantly, with no tween at all — the same SSR-safematchMediahook used byTruncatedText's no-hover detection andMessageScroller's reduced-motion handling.- Digits use
tabular-numsso the layout never jitters horizontally as the character count changes mid-animation (e.g.99→100). - Server-safe: the initial render (server AND client) always shows the static final value — there is no hydration mismatch to reconcile.
| Contract | States tested |
|---|---|
| Behaviour | default, empty |
| Accessibility | live, status-announcement, semantic-html |
| Visual | default, empty |