Docs
Installation
A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its dependencies and any missing npm packages, and installs them straight into your project.
npx shadcn add https://staaarter.com/r/animated-counter-row.jsonPrefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/stats/stats5.tsx instead.
Usage
The file also exports stats5Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.
import { Stats5, stats5Demo } from "@/components/blocks/stats/stats5"; export default function Page() { return <Stats5 {...stats5Demo} />; }
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| heading | string | undefined | Optional heading above the stat row. |
| description | string | undefined | Optional supporting text under the heading. |
| stats | CounterStat[] | none | The stat entries; each value is the animation's target number. |
| className | string | none | Extra classes for the outer section element. |
Types
type CounterStat = { value: number; label: string; prefix?: string; // e.g. "$" suffix?: string; // e.g. "%" or "+" };
Behavior notes
- The count-up is real, local-state interactivity: a useCountUp hook runs a fixed 24-step setInterval (30ms per step) started in a useEffect on mount, incrementing every number from 0 toward its target in lockstep. This is the same pattern used by the Hero category's hero1 counters.
- The animation is intentionally NOT scroll-triggered. An earlier attempt used IntersectionObserver to start the count-up only when the block scrolled into view, but this block's live preview renders inside an iframe via a React portal (the component's JS runs in the parent window while its DOM lives in the iframe's document), and the observer's implicit root resolved against the wrong window and never fired, even with an explicit root element. Animating unconditionally on mount is the fix that reliably works in that architecture.
- Because it's mount-triggered rather than scroll-triggered, the counters animate immediately every time the block is rendered, including in the category grid's and sibling-list's card thumbnails, not just on a full page load.
- The demo props live in a separate stats5.demo.tsx sibling file (not exported from the "use client" component file itself), since a demo-props object exported from a client module resolves to undefined when read from the server-rendered preview shell.
More Stats Blocks
View all →Simple Four Stat Row
A plain 4-column row of big numbers with labels, no icons or chrome.
Stats With Icons
Bordered stat tiles, each topped with a lucide icon above the number.
Big Hero Stat
One dominant, oversized stat with smaller supporting stats below it.
Stats With Progress Bars
A vertical list of stats, each paired with a horizontal progress bar toward a goal.
Dashboard Style Grid
A dense analytics-dashboard grid with trend deltas and inline sparklines.
Before After Comparison
Two-column before/after comparison of the same metrics, with the after column highlighted to signal improvement.