Animated number transitions with full Intl.NumberFormat support. Lightweight, pure CSS animations, zero external dependencies.
From the Betterlytics analytics platform.
- Smooth digit rolling animations with configurable duration
- Pure CSS animations — no JavaScript animation libraries
- Full
Intl.NumberFormatsupport (currencies, percentages, any locale) - Automatic width transitions when numbers grow or shrink
- Symbol cross-fade for currency symbols, decimal separators, etc.
- Respects
prefers-reduced-motionfor accessibility - SSR-safe with hydration mismatch prevention
- Zero dependencies beyond React
- Tiny footprint (~5KB minified)
npm install react-number-roll
# or
pnpm add react-number-roll
# or
yarn add react-number-rollimport { NumberRoll } from "react-number-roll";
function PriceDisplay({ price }) {
return (
<NumberRoll
value={price}
formatOptions={{ style: "currency", currency: "USD" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
value |
number |
required | The number to display |
locales |
Intl.LocalesArgument |
'en-US' |
Locale for number formatting |
formatOptions |
Intl.NumberFormatOptions |
undefined |
Options passed to Intl.NumberFormat |
duration |
number |
600 |
Animation duration in milliseconds |
withTextSelect |
boolean |
false |
Allow text selection of the formatted value |
className |
string |
undefined |
Additional CSS classes for the outer wrapper |
<NumberRoll
value={1234.56}
formatOptions={{ style: "currency", currency: "EUR" }}
/><NumberRoll
value={0.8542}
formatOptions={{ style: "percent", minimumFractionDigits: 2 }}
/><NumberRoll
value={1500000}
formatOptions={{ notation: "compact", maximumFractionDigits: 1 }}
/><NumberRoll value={count} duration={300} />The component respects the user's motion preferences. When prefers-reduced-motion: reduce is set, animations are disabled automatically.
The component uses CSS custom properties that you can override in your own styles:
.ba-number-roll-root {
--ba-digit-width: 0.65em; /* Width of each digit */
--ba-mask-width: 2em; /* Horizontal fade width */
--ba-mask-bleed: 0.4em; /* Vertical fade bleed */
}You can also target these classes for more advanced styling:
.ba-number-roll-outer- Outer wrapper.ba-number-roll-root- Inner container with CSS variables.ba-digit-reel-wrapper- Individual digit container.ba-symbol-slot- Symbol (comma, decimal, currency) container
Requires browsers with support for:
- CSS
lhunit (line-height relative) Intl.NumberFormat
Chrome 77+, Edge 77+, Safari 16.4+, Firefox 120+
MIT