Stats Hero
A free animated hero section where the stats are the motion.
- Automated axe check
- Reduced-motion tested
- SSR build verified
- GSAP
- 2 runtime packages
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 is built with GSAP and ScrollTrigger, 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.
The numbers behind every launch
Stats Hero keeps the first screen calm and typographic, then lets the figures do the moving: each metric counts up from zero the moment it scrolls into view.
Teams shipping weekly
Uptime last quarter
Processed each year
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="The numbers behind every launch"
subtitle="A calm typographic hero where the stats do the moving."
cta={{ label: "Get started", href: "/signup" }}
stats={[
{ value: 42000, suffix: "+", label: "Teams shipping weekly" },
{
value: 99.98,
suffix: "%",
decimals: 2,
label: "Uptime last quarter",
},
{
value: 1.8,
prefix: "$",
suffix: "B",
decimals: 1,
label: "Processed each year",
},
]}
/>
);
}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, stat values and the inverted 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);
}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.