Stats Hero
A free animated hero section where the stats are the motion.
Turn no-shows back into appointments
Onward texts your waiting list the moment a slot opens and books the first patient who answers, usually inside four minutes and without a single front-desk call.
1,180+
Clinics on the platform
31.4%
No-show slots refilled
3.8 min
To fill an open slot
Stats Hero is a free animated hero section for Next.js and React that pairs a calm typographic headline with a row of live counters. It reveals its blocks in one staggered Motion entrance, is styled with Tailwind, and composes the Count Up component through a registry dependency, so each stat counts up from zero the moment it scrolls into view.
You pass a title, an optional subtitle, one call to action and up to four stats, and the section handles the rest: the headline, subtitle, CTA and stat row rise in sequence as whole blocks, then the counters settle on their real numbers. The final formatted values are rendered in the server HTML, so crawlers and reduced-motion users always read the finished figures, and tabular numerals keep the layout perfectly still while the counts run.
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/hero-statsUsage
import { HeroStats } from "@/components/hero-stats";
export default function Page() {
return (
<HeroStats
title="Turn no-shows back into appointments"
subtitle="Onward books the first patient on your waiting list the moment a slot opens."
cta={{ label: "Book a clinic walkthrough", href: "/demo" }}
stats={[
{ value: 1180, suffix: "+", label: "Clinics on the platform" },
{
value: 31.4,
suffix: "%",
decimals: 1,
label: "No-show slots refilled",
},
{
value: 3.8,
suffix: " min",
decimals: 1,
label: "To fill an open slot",
},
]}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | required | Headline copy, rendered as the section's single h1. |
| subtitle | string | undefined | Supporting copy rendered below the headline. |
| cta | { label: string; href: string } | required | Primary call to action, rendered as a real anchor. |
| stats | { value: number; label: string; prefix?: string; suffix?: string; decimals?: number }[] | required | One to four stats rendered with Count Up counters. |
| className | string | undefined | Additional classes merged onto the section root. |
Customisation
Stats Hero declares no tokens of its own; it is a calm typographic section that consumes the global semantic tokens directly. Override --foreground for the headline and stat values, --primary and --primary-foreground for the call to action, --muted for the supporting copy and stat labels, and --border for the rule above the stat row, from :root or any ancestor of the hero, to retheme the whole section without touching the code:
:root {
--foreground: var(--color-neutral-50);
--muted: oklch(from var(--color-neutral-50) l c h / 0.7);
--primary: var(--color-brand-500);
--primary-foreground: var(--color-neutral-950);
}Frequently asked questions
- Is Stats Hero free for commercial use?
- Yes. Stats Hero is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Does Stats Hero affect performance or accessibility?
- The entrance animates transforms and opacity only, inside space the layout has already reserved, and the counters use tabular numerals so their width never changes while counting, which keeps layout shift at zero. The final numbers are rendered in the server HTML and each counter carries its finished value as an accessible name, so screen readers never hear intermediate counts. The call to action is a real anchor with a visible focus ring, and with reduced motion enabled the full section renders immediately with the final figures in place.
- How do I format the numbers in the stat row?
- Each stat accepts prefix, suffix and decimals, so you can render values like $1.8B or 99.98% directly. Grouping and decimal separators come from a fixed en-US Intl.NumberFormat inside the Count Up component, which keeps server and client output identical.