Odometer Stats
A free logo and stats section with locale-aware rolling digits for React.
- 128,500+
Production deployments
- 99.98%
Platform uptime
- £3.7M
Revenue influenced
- -42.5%
Release time change
Customise
Code
<StatOdometer stats={stats} />Odometer Stats is a free animated stats counter React section for Next.js and React, styled with Tailwind and enhanced with Motion. It formats one to six metrics in a chosen locale, then rolls only the numeric glyphs through fixed digit strips when the section first enters view.
Every complete value and label is present in the server HTML before JavaScript runs. The rolling layer is decorative and hidden from assistive technology, while reduced-motion users and browsers without IntersectionObserver keep the readable final values without creating animation controls.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/stat-odometerUsage
import { StatOdometer } from "@/components/stat-odometer";
const stats = [
{
id: "deployments",
value: 128500,
label: "Production deployments",
suffix: "+",
},
{
id: "uptime",
value: 99.98,
label: "Platform uptime",
suffix: "%",
maximumFractionDigits: 2,
},
{
id: "revenue",
value: 3.7,
label: "Revenue influenced",
prefix: "£",
suffix: "M",
maximumFractionDigits: 1,
},
];
export function Example() {
return (
<StatOdometer
stats={stats}
locale="en-GB"
direction="alternate"
columns={3}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| stats | ReadonlyArray<{ id; value; label; prefix?; suffix?; maximumFractionDigits? }> | required | One to six uniquely identified stats. Non-finite values render a safe static em dash. |
| locale | string | "en-GB" | Intl.NumberFormat locale. Invalid or unsupported locales fall back deterministically to en-GB. |
| duration | number | 1.2 | Digit-roll duration in seconds, clamped to 0.3 to 2.5. |
| stagger | number | 0.07 | Delay between stat starts in seconds, clamped to 0 to 0.2. |
| digitHeight | number | 52 | Fixed digit-line height in CSS pixels, clamped to 32 to 88. |
| direction | "up" | "down" | "alternate" | "up" | Decorative wheel direction. Alternate changes direction by numeric digit index. |
| columns | 2 | 3 | 4 | 4 | Maximum number of grid columns at wide breakpoints. |
| radius | number | 22 | Stat-card radius in CSS pixels, clamped to 0 to 44. |
| className | string | undefined | Additional classes merged onto the section. |
Customisation
Use the six playground controls to tune motion and geometry without changing the preview data. The three component tokens set the digit accent, card surface and separators, so the odometer can follow a product theme without editing its source:
<div className="[--odometer-accent:var(--primary)] [--odometer-panel:var(--card)] [--odometer-divider:var(--border)]">
<StatOdometer
stats={stats}
duration={1.5}
stagger={0.1}
digitHeight={60}
direction="alternate"
columns={3}
radius={28}
/>
</div>Frequently asked questions
- Is Odometer Stats free for commercial use?
- Yes. Odometer Stats is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Does the digit animation remain accessible with reduced motion?
- Yes. Assistive technology receives one complete final value and label per list item, never the decorative wheel contents. Reduced motion and unsupported IntersectionObserver paths render the final static values without creating animation controls.
- How do I format currencies, percentages and decimal values?
- Set locale on the component, then use prefix, suffix and maximumFractionDigits on each stat. Signs and locale separators stay static while only numeric glyphs roll.