React Animated Counter mit rollenden Ziffern

Du brauchst einen React Animated Counter für einen Umsatz, eine Live-Besucherzahl oder einen Preis-Umschalter. Die erste Version ist meist ein setInterval, das eine Zahl im State hochzählt, bis sie das Ziel erreicht. Dann ändert sich die Zahl mitten im Zählen und startet wieder bei null, der Text zittert hin und her, weil eine 1 schmaler ist als eine 8, ein Besucher aus Deutschland sieht 12,480.00 statt 12.480,00, und ein Screenreader sagt vierzig Zahlen hintereinander an. Dieser Guide zeigt, was ein produktionsreifer Zähler braucht, welche Props im Animated Counter von Wingo UI wichtig sind und wie die Stat Card ihn in eine Dashboard-Kachel setzt.
Was muss ein React Animated Counter können?
Er animiert vom Wert auf dem Bildschirm aus, hält seine Breite, formatiert passend zur Locale, gibt Screenreadern einen einzigen Wert und beachtet Reduced Motion. Im Detail:
- Vom sichtbaren Wert aus animieren. Ändert sich die Zahl mitten in einer Animation, soll der Zähler von den Ziffern aus weiterlaufen, die gerade zu sehen sind, statt neu anzufangen. Preise, Punktestände und Live-Zahlen ändern sich oft, deshalb ist das wichtiger als die erste Animation.
- Eine stabile Breite. Tabellenziffern (
font-variant-numeric: tabular-nums, in Tailwindtabular-nums) geben jeder Ziffer dieselbe Breite, sodass die Zahl nur wächst, wenn eine Stelle dazukommt. - Formatierung nach Locale. Tausender- und Dezimaltrennzeichen hängen von der Locale ab.
Intl.NumberFormatkennt sie schon, also soll der Zähler dort nachfragen, statt ein Komma fest einzubauen. - Ein Wert für Screenreader. Die bewegten Ziffern sind Dekoration. Hilfstechnologien sollen die formatierte Endzahl genau einmal bekommen.
- Reduced Motion. Bei
prefers-reduced-motion: reducesoll sich die Zahl an Ort und Stelle aktualisieren, ganz ohne Rollen.
Count-up oder Odometer: welche Art animierter Zahl brauchst du?
Nimm einen Count-up für eine einmalige Einblendung und einen Odometer für einen Wert, der sich laufend ändert. Das sind die beiden Arten von React Animated Numbers. Ein Count-up lässt den ganzen Wert von A nach B laufen und zeigt jede Zahl dazwischen. Das passt zu einer einmaligen Einblendung („12.000 Kunden“). Ein Odometer, also ein rollender Zähler wie ein Kilometerzähler, gibt jeder Ziffer ihr eigenes senkrechtes Rad und rollt nur die Ziffern, die sich geändert haben. Bei Werten, die in Bewegung bleiben, liest sich das besser: Ein Preis, der von 1.249 auf 1.251 steigt, bewegt zwei Räder, statt durch jede Zahl dazwischen zu flackern.
Diese Optionen tauchen auf, wenn du nach einem React Odometer oder einer Counter-Komponente suchst. Die Fakten stammen aus der öffentlichen Doku und dem README der Projekte, Stand Oktober 2026.
NumberFlow ist die bessere Wahl, wenn der Zähler selbst die volle Ausgabe von Intl.NumberFormat liefern soll, etwa kompakte Schreibweise (1.2K) oder Prozent, denn es formatiert mit dem ganzen Options-Objekt. react-countup reicht für eine einzelne Einblendung auf einer Landingpage. Der Animated Counter passt, wenn du den Quellcode in deinem Repo, Tailwind-Klassen und dieselben Tokens und Spring-Presets wie im Rest deiner UI willst.
Welche Props braucht der Animated Counter?
Einen: value. Für alles andere gibt es einen Standardwert, mit dem der Zähler schon fertig aussieht.
Die Props, die du am häufigsten änderst:
decimals(Standard0, bis 15): Der Wert wird auf diese Genauigkeit gerundet, damit die Räder immer auf einer ganzen Ziffer landen.duration(Standard0.6Sekunden): ungefähr die Zeit, bis eine Ziffer zur Ruhe kommt. Für Werte, die sich jede Sekunde ändern, setzt du ihn niedriger.bounce(Standard0.18): wie stark die Spring der Räder überschwingt, von 0 bis 1.padStart(Standard1): die Mindestzahl an Vorkommastellen, mit Nullen aufgefüllt, damit ein Timer oder ein Punktestand seine Breite hält, wenn er eine Zehnerpotenz überschreitet.prefixundsuffix: ein Währungszeichen, eine Einheit oder ein Icon. Sie animieren nie, gleiten aber mit, wenn sich die Breite ändert.fadeundfadeSize(Standardtrueund22): die weiche Blende oben und unten in jedem Ziffernfenster. Schaltfadeaus, wenn du einen harten, mechanischen Schnitt willst.
Zieh über das Lineal unten. Die Ziffern rollen nach oben, wenn die Zahl wächst, und wieder nach unten, wenn sie schrumpft. Eine neue Stelle gleitet herein, und die Trennzeichen wandern mit.
$ npx wingo-ui@latest add animated-counterWie style ich einen animierten Zähler mit Tailwind?
Lass size, font und weight auf ihrem Standard inherit, dann verhält sich der Zähler wie Text: Eine Klasse am Zähler oder an seinem Elternelement bestimmt die Größe. Ein Tailwind Animated Counter braucht dann keine zusätzlichen Props: Eine responsive Größe besteht einfach aus responsiven Klassen.
Das Root-Element trägt schon tabular-nums. Darin hat jede Ziffernspalte data-slot="animated-counter-digit" und jedes Trennzeichen data-slot="animated-counter-mark". Beide erreichst du mit einer Arbitrary Variant, zum Beispiel [&_[data-slot=animated-counter-mark]]:opacity-60 für dezentere Kommas. Für eine eigene Farbe gibt es color (Standard currentColor); currentColor folgt dem Text und funktioniert im Light und im Dark Mode ohne zusätzliche Klassen.
Wie formatiere ich die Zahl mit Intl?
Gib locale mit. Der Zähler ruft einmal Intl.NumberFormat(locale).formatToParts() auf und holt sich daraus die Tausender- und Dezimaltrennzeichen der Locale: en-US schreibt 1,234.5, de-DE 1.234,5 und fr-FR 1 234,5 mit einem schmalen Leerzeichen. Setz die Locale einmal für die ganze App mit UIProvider, dann übernimmt jeder Zähler sie.
Ein explizit gesetzter separator oder decimalSeparator hat immer Vorrang vor der Locale. So schaltest du die Gruppierung für eine Jahreszahl oder eine Bestellnummer ab (separator=""). grouping="indian" setzt das erste Trennzeichen nach den letzten drei Ziffern und danach alle zwei Ziffern: 12,34,567.
Zwei Grenzen solltest du kennen. Der Zähler holt aus Intl nur die Trennzeichen, nicht den komplett formatierten String. Ein Währungszeichen ist also dein prefix oder suffix, und wo es steht, entscheidest du. Außerdem zeichnet er immer die Ziffern 0 bis 9. Soll das Symbol dort stehen, wo die Locale es vorsieht, oder brauchst du Prozent oder kompakte Schreibweise, nimm die Stat Card weiter unten: Sie formatiert mit Intl und wechselt bei kompakten und Prozentwerten zu einem Count-up.
Wie geht ein Zähler mit Werten um, die sich ständig ändern?
Jedes Rad zielt von dort aus, wo es gerade steht. Genau das brauchst du, wenn du in React eine Zahl animieren willst, die nie stillsteht. Ändert sich der Wert, während eine Ziffer noch rollt, setzt die Spring von der sichtbaren Ziffer aus neu an, statt erst die alte Drehung zu beenden. Eine Zahl, die sich jede Sekunde ändert, dreht also flüssig, statt zu ruckeln. Die Richtung folgt der Änderung: Die Ziffern rollen nach oben, wenn der Wert wächst, und nach unten, wenn er schrumpft.
Bei einem Live-Wert verkürzt du die Dauer, damit die Räder nah an der echten Zahl bleiben:
Für einen Countdown füllst du Minuten und Sekunden auf zwei Stellen auf und schaltest die Gruppierung ab, damit sich die Breite nie ändert:
Brauchst du Tage, Stunden und Beschriftungen, ist die Pro-Komponente Countdown genau dafür gebaut.
Wie zähle ich hoch, sobald die Zahl ins Bild scrollt?
Der Zähler zeigt seinen Wert beim ersten Paint ohne Animation. So stimmen das Server-HTML und der erste Frame. Damit er beim Scrollen hochrollt, startest du bei null und gibst den echten Wert weiter, sobald das Element sichtbar ist:
Der Haken: Im Server-HTML steht jetzt 0, und genau das sehen Crawler und Leser ohne JavaScript. Bei einer Marketing-Zahl, die für die Suche zählt, schreib den echten Wert zusätzlich in den Text daneben. Oder nimm die Stat Card: Ihr Server-HTML und ihr erster Paint zeigen schon die Endzahl, und sie zählt erst von null hoch, wenn sie ins Bild scrollt.
Ist ein animierter Zähler barrierefrei?
Ja, wenn die bewegten Teile versteckt sind. Der Animated Counter rendert die rollenden Räder mit aria-hidden und legt die formatierte Zahl samt Minuszeichen in einen visuell versteckten Span daneben. prefix und suffix bleiben außerhalb des versteckten Teils. Mit einem $ als Text-Prefix liest ein Screenreader also einmal „$12,480.00“ vor und nie die Ziffern, die vorbeirollen. Gib einem Icon als Prefix ein eigenes aria-hidden oder ein Label.
Dazu kommen zwei Regeln:
- Pack keine tickende Zahl in
aria-live. Eine Besucherzahl, die sich alle zwei Sekunden ändert, würde den Nutzer alle zwei Sekunden unterbrechen. Sag nur Änderungen an, die wirklich zählen, in einer eigenen Live-Region mitaria-live="polite"und in einem Tempo, dem ein Mensch folgen kann. - Reduced Motion heißt: kein Rollen. Wenn das System reduzierte Bewegung anfordert, setzt der Zähler jede Ziffer direkt auf ihren neuen Wert und ändert die Größe sofort. Stellen, die dazukommen oder wegfallen, wechseln ohne Übergang. Der Hook dahinter liest die Media Query erst nach der Hydration, sodass Server und Client dasselbe Markup rendern. Wie dieses Muster im Detail funktioniert, steht im Guide zu prefers-reduced-motion in React.
Das Rollen selbst ist eine Motion-Spring (ihre visualDuration ist duration, ihr Bounce ist bounce) auf einem Motion Value, der transform steuert. React rendert also nicht in jedem Frame neu. Willst du die Bewegung über bounce hinaus feinjustieren, erklärt der Guide zu Spring-Presets, was Bounce und Visual Duration bewirken.
Wann nehme ich stattdessen die Stat Card?
Wenn die Zahl eine Dashboard-Kennzahl mit Label, Änderungs-Pill und vielleicht einer Sparkline ist. Die Stat Card hat drei Animationsmodi:
animation="count"(Standard): zählt beim ersten Mal, wenn die Karte ins Bild scrollt, von null hoch (900 ms, Ease-out), bei späteren Änderungen vom vorherigen Wert aus.animation="roll": der Odometer des Animated Counter, für Live-Zahlen. Er funktioniert mitformat="number"undformat="currency"; die Karte setzt das Währungszeichen dorthin, wo die Locale es vorsieht. Andere Formate fallen auf count zurück.animation="none": statisch.
Screenreader hören einen einzigen Satz mit dem Endwert und der Änderung, etwa „$128,450, up 12.4% vs. last month“. Bei Reduced Motion erscheinen Zahl und Diagramm sofort im Endzustand.
$ npx wingo-ui@latest add stat-cardEin komplettes Dashboard aus diesen Kacheln baut das Tutorial zum Next.js Admin Dashboard.
Welche typischen Fehler gibt es bei animierten Zählern?
- Proportionale Ziffern. Ohne Tabellenziffern ist 1.111 schmaler als 8.888, und der Text verschiebt sich bei jeder Änderung. Der Animated Counter setzt
tabular-numsund macht jede Spalte zusätzlich so breit wie ihre breiteste Ziffer, für Schriften ohne Tabellenziffern. - Einen String übergeben.
valueist eine Zahl. Formatier sie über die Props, nicht vorher mittoLocaleString(). - Riesige oder unsichere Werte. Der Zähler deckelt den skalierten Wert bei
Number.MAX_SAFE_INTEGER, weil Ziffern darüber hinaus nur Rauschen sind. Halte Geldbeträge auf dem Server in Cent und teile erst für die Anzeige. - Trennzeichen, die der Locale widersprechen. Wenn
separatorgesetzt ist, hat er Vorrang vorlocale. Lass ihn weg, wenn du die Trennzeichen der Locale willst. - Eine lange Zahl auf einem 360px breiten Smartphone. Ein Wert in
text-7xlmit zwei Nachkommastellen kann über eine schmale Karte hinauslaufen. Nimm responsive Größenklassen oder in Karten eine kleineresize.
Wie baue ich ihn in mein Projekt ein?
Führ npx wingo-ui@latest add animated-counter aus. Die CLI kopiert den Quellcode nach components/ui, ergänzt die Helfer motion und ui-config, die die Komponente importiert, und installiert motion. Der Animated Counter ist kostenlos; die Stat Card ist eine Pro-Komponente (Preise). Weitere Deep Dives zu einzelnen Komponenten findest du in der Kategorie Komponenten-Guides, und der Guide zu React-Formularkomponenten wendet dieselben Regeln für Barrierefreiheit und mobile Nutzung auf jedes Formularelement an.
Häufige Fragen
Wie animiere ich in React eine Zahl, wenn sie sich ändert?
Halte die Zahl im State und gib sie an eine Komponente weiter, die zwischen altem und neuem Wert animiert, etwa einen Odometer-Zähler oder einen Count-up-Tween. Animiere nur transform und opacity und starte jede Animation bei dem Wert, der gerade zu sehen ist, damit sich schnelle Updates nicht aufstauen.
Was ist der Unterschied zwischen einem Count-up und einem Odometer-Zähler?
Ein Count-up lässt die ganze Zahl durch alle Zwischenwerte laufen und rendert den Text in jedem Frame neu. Ein Odometer rollt jede Ziffer auf ihrem eigenen Rad zur neuen Ziffer, sodass sich nur die geänderten Ziffern bewegen und die Breite stabil bleibt.
Wie mache ich einen animierten Zähler barrierefrei?
Versteck die bewegten Ziffern vor Hilfstechnologien und gib den formatierten Endwert als normalen Text aus. Pack keine Zahl, die jede Sekunde tickt, in eine aria-live-Region, sonst liest ein Screenreader jedes Update vor.
Beachtet ein animierter Zähler prefers-reduced-motion?
Nur wenn er die Media Query prüft. Der Animated Counter von Wingo UI und NumberFlow tun das standardmäßig; das README von react-countup erwähnt es nicht, dort prüfst du die Einstellung also selbst.
Ist der Animated Counter von Wingo UI kostenlos?
Ja. Der Animated Counter ist eine kostenlose Komponente, die du mit npx wingo-ui@latest add animated-counter installierst. Die Stat Card, die ihn für Dashboard-Kacheln nutzt, ist eine Pro-Komponente.
- Animation
- Zahlen
- Dashboard
- Barrierefreiheit
- React


