Number flow

Free · MIT

Digits roll to the new value with locale formatting, prefixes and suffixes.

MarkdownOpen in v0
Open in v0

Installation

$ npx shadcn@latest add https://goodui.dev/r/number-flow.json

The file lands in components/goodui/number-flow.tsx and is yours to edit. With the @goodui registry added, npx shadcn@latest add @goodui/number-flow works too.

Usage

import { NumberFlow } from "@/components/goodui/number-flow"

export function PlanPrice({ yearly }: { yearly: boolean }) {
  return (
    <div className="flex items-baseline gap-1">
      <NumberFlow
        value={yearly ? 39 : 49}
        format={{ style: "currency", currency: "USD", maximumFractionDigits: 0 }}
        className="text-4xl font-semibold tracking-tight"
      />
      <span className="text-sm text-muted-foreground">per seat / month</span>
    </div>
  )
}

When to use

Use it for
  • A live value that changes while the user watches: revenue on a dashboard, a cart total, seats left.
  • Prices that switch with a monthly/yearly toggle, so the change is visible instead of a jump.
  • Small counts next to controls (+ / - steppers) where each change should feel physical.
Reach for something else
  • A number that should count up once when it scrolls into view: use counter-up.
  • Showing the change itself (+12.4%) rather than the value: use delta-badge.
  • Values in a dense table that update often: use cell-flash, which signals the direction without moving the layout.

Examples

Dashboard revenue in another locale

<NumberFlow
  value={48295.5}
  locale="de-DE"
  format={{ style: "currency", currency: "EUR" }}
  className="text-3xl font-semibold"
/>

Percent with prefix and suffix

<NumberFlow value={0.684} format={{ style: "percent", maximumFractionDigits: 1 }} />
<NumberFlow value={1284} prefix="~" suffix=" bookings" />

API reference

PropTypeDefault
value*
Number to show. Changing it rolls each digit to its new value.
number—
format
Intl.NumberFormat options, e.g. { style: "currency", currency: "USD" }.
Intl.NumberFormatOptions—
locale
Locale passed to Intl.NumberFormat ("de-DE" gives 1.234,5). Defaults to the GooduiLocaleProvider language, else en-US.
string—
prefix
Text placed before the formatted number, e.g. "~".
string""
suffix
Text placed after the formatted number, e.g. " / mo".
string""
className
Classes merged onto the root element.
string—

Accessibility

  • The formatted value is rendered once in an sr-only span; the rolling digit columns are aria-hidden, so screen readers never read ten digits per column.
  • There is no aria-live region: wrap it in your own live region if a change must be announced.

Motion

  • Each digit is a 0-9 column that slides on a spring (stiffness 140, damping 20, mass 0.8). A 9 going to 0 rolls back down the column through every digit, it does not wrap.
  • Separators, currency symbols, prefix and suffix swap instantly; only digits roll.
  • Characters are keyed by their distance from the end, so units stay in their column when the number gains or loses digits.
  • Reduced motion: the transition becomes duration 0, so digits snap to the new value.
  • Each digit is one motion span animating transform only. There are no timers; nothing runs while the value is stable.

Notes for AI

Coding agents read these rules through MCP and llms.txt, or paste this page with Copy page.

  • Pass a number to value and formatting through format (Intl.NumberFormatOptions) and locale; do not pre-format it into a string.
  • For currency use format={{ style: "currency", currency: "USD" }}, not prefix="$".
  • It animates on value change only; it does not count up on mount. Use counter-up for that.
  • Give the font size and weight through className; the component sets tabular-nums itself.
  • There is no labels prop: the only text it renders is the formatted value.

FAQ

Does it animate on first render?

No. initial is false, so it shows the value immediately and only rolls when value changes. Use counter-up for a count from zero.

Can it show decimals and currencies?

Yes. Anything Intl.NumberFormat formats works: currency, percent, compact notation, fixed fraction digits, any locale. Each digit in the output rolls.

Related