A high-performance, CSS-only animated counter for React that never re-renders on value updates.
Ideal for dashboards, KPIs, and animated counters where performance and visual smoothness matter.
LIGHT Package Size:
- ⚡ Zero re-renders — DOM is fully static after mount
- 🔁 2 modes:
- Static: Only changed digits animate
- Rolling: Seamless jackpot-style rolling using duplicated digit strings
- 🧩 Accepts numbers or formatted strings
- 🏷 Optional unit label with positioning
- 🧠 Ripple-style animation with dynamic delay per digit
This component avoids React re-renders by offloading all animation logic to CSS variables and direct DOM manipulation. Every digit is pre-rendered via CSS content (:before) and animated with transform.
In rolling mode, digits animate smoothly from their current index to index + 10 (which wraps visually), and snap back after the transition ends.
npm install react-strp-counter
or
yarn add react-strp-counter
// import STRPCounter
import {STRPCounter} from 'react-strp-counter';
// import CSS
import 'react-strp-counter/css';
<STRPCounter
value={1234567.89} // REQUIRED
fontSize="48px" // optional
minLength={9} // optional
delimiter="," // optional
decimalSeparator="." // optional
unitLabel="USD" // optional
unitLabelPosition="left" // optional
rollingMode={true} // optional
stepDuration={0.05} // optional
easing={"cubic-bezier(0.33,0.81,0.1,1.02)"} // optional
/>
Prop | Type | Required | Default | Description |
---|---|---|---|---|
value |
number | string |
✅ | — | The numeric value or formatted string to render |
fontSize |
string |
❌ | "28px" |
Font size (used as --strp_fontsize CSS variable) |
minLength |
number |
❌ | — | Pad with zeroes on the left to reach minimum character length, used to avoid layout shifts when your number has to add a digit from the left side, optional, but I highly suggest to always use this |
rollingMode |
boolean |
❌ | false |
If true, enables jackpot-style rolling animation |
stepDuration |
number |
❌ | 0.05 | Optional, used with rollingMode, Per-digit step duration (in seconds) used for timing delays |
delimiter |
string | false |
❌ | false |
Thousands delimiter (e.g. ",", " ") |
decimalSeparator |
string | false |
❌ | false |
Decimal point (e.g. "."), always add 2 decimals if you use this |
unitLabel |
string | React.ReactNode |
❌ | — | Optional unit (e.g. "$", "kg", "<div /> ", "<svg /> " etc.) |
unitLabelPosition |
'left' | 'right' |
❌ | "left" |
Where to place the unit label |
easing |
string | false |
❌ | "cubic-bezier(0.33, 0.81, 0.1, 1.02)" |
If set to "false" component will use "linear" instead. Feel free to pass your custom easing |
Use tabular fonts (e.g. Roboto Mono, JetBrains Mono, Menlo, SF Mono) for perfect alignment.
Font used in demo is Big Shoulders Stencil
You are required to supply your own FONT.
The package does not include any fonts to make it as lightweight as possible.
Code below:
.strp_counter_wrap {
--strp_fontfamily: 'YOUR CUSTOM FONT FAMILY';
}
or
:root {
--strp_fontfamily: 'YOUR CUSTOM FONT FAMILY';
}
Everything inside the component is forced to render in LTR state, if you supply a RTL unitLabel please force it to be rendered as RTL
.strp_counter_wrap .YOUR_CUSTOM_UNITLABEL {
direction: rtl !important;
}
- Digits animate directly to the new value using CSS transitions.
- No infinite-roll illusion; transitions go straight to the next index.
- Transitions are smooth but not "slot machine style".
- Ideal for standard animated counters and real-time updates.
- Digits roll upward through a sequence of 10 values to reach the next digit.
- Designed to mimic a jackpot / slot machine animation.
- Digits on the right change first; left digits delay proportionally.
- After rolling, digits snap back to correct value without transition (visually seamless).
- Ideal for flashy counters, jackpots, or game-like UIs.
Digits that change closer to the right animate first. Those to the left wait slightly longer.
This creates a smooth ripple reminiscent of jackpot reels or odometers.
If a digit doesn’t change, it doesn't animate.
This package is designed to animate without triggering any React re-renders or layout thrashing. No animations are handled via JavaScript after setup. All transitions are GPU-accelerated and run purely via CSS variables.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
MIT