Skip to content
Template Empire
Browse components

Count Up

A free count up text effect for stats and metrics, built on Motion.

Northfield Solar

12,847+

Rooftops switched on

99.71%

Inverters reporting daily

$18.4M

Saved on bills last year

Illustrative annual-report data for a fictional solar operator, covering the twelve months to June.

Customise

1.2s

Code

<TextCounter value={12847} suffix="+" />

Count Up is a free text effect component for Next.js and React that animates a number from zero to its final value with Motion. The count starts once when the wrapper scrolls into view, runs over the library's 1.2 second motion beat with an expo ease, and is styled with Tailwind.

The final formatted value, including prefix, suffix and Intl.NumberFormat grouping, is rendered as readable text in the server HTML. It reserves space behind the animated number and remains available to assistive technology, including with the default span wrapper. Reduced motion immediately restores that value, even during a count. Once counting has started, changing the value or formatting settles immediately to the latest props instead of starting another count.

A native intersection observer starts the count when the wrapper is actually visible within the viewport's leading 85%, or entirely in view, respecting clipped and nested scrolling containers. Until then the visible number shows zero while the final value stays in the accessible text, and an item skipped entirely before observation counts when first seen later. Without IntersectionObserver, the final value stays visible without animation. After the count nothing keeps running.

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/text-counter

Usage

import { TextCounter } from "@/components/text-counter";

export function Example() {
  return (
    <p className="text-5xl font-semibold">
      <TextCounter value={12847} suffix="+" /> components installed
    </p>
  );
}

Props

PropTypeDefaultDescription
valuenumberrequiredFinal value; rendered formatted in the SSR HTML.
durationnumber1.2Count duration in seconds (--dur-4).
decimalsnumber0Fraction digits in the formatted output.
prefixstring""Rendered before the number (e.g. "$").
suffixstring""Rendered after the number (e.g. "+", "%").
localestring"en-US"Fixed Intl.NumberFormat locale so SSR and client formatting match.
asElementType"span"Element rendered as the wrapper.
classNamestringundefinedAdditional classes merged onto the wrapper.

Customisation

Count Up deliberately ships without component-level CSS variables. Formatting is controlled entirely through props: decimals, prefix and suffix shape the output, the fixed locale sets grouping and decimal separators, and duration paces the count against your motion system:

<TextCounter
  value={99.98}
  decimals={2}
  suffix="%"
  locale="de-DE"
  duration={2}
/>

Frequently asked questions

Is Count Up free for commercial use?
Yes. Count Up is available under MIT with the Commons Clause condition. You may use and modify it in personal or commercial projects, including client work, while retaining the licence notice in the source. You may not sell the components themselves or repackage the catalogue as a competing component library, template pack or UI kit. See LICENCE.md in the repository for the full terms.
Does Count Up cause layout shift or hurt SEO?
No. The server HTML contains the final formatted value, so crawlers and no-JS visitors read the real number. The unchanged final text reserves its width behind the animated tabular numerals. With reduced motion enabled the final value renders immediately with no counting, and enabling the preference during a count restores it immediately too.
How do I format the number as a currency or percentage?
Use the prefix and suffix props for symbols, the decimals prop for fraction digits, and the locale prop for grouping and decimal separators. The locale is fixed rather than read from the browser, so server and client output always match.

Related components

Want the full page this belongs to?Template Empire builds complete Next.js templates with this motion system throughout. Browse the paid templates that pair with these free components.Explore Template Empire templates