Sora UI

Number Flow

An animated, digit-by-digit number counter with a smooth rolling odometer effect, powered by Motion.

Made by Sora

Animated number counter with tabbed examples — currency, input overlay, and countdown. Switch tabs above the preview to explore each pattern.

Loading...

Examples

The preview includes three tabbed patterns:

TabPattern
CurrencyFormatted counter with increment controls
InputNative number input with a NumberFlow overlay — typing skips animation, stepper buttons animate
CountdownHH:MM:SS with trend={-1} so digits roll downward

Installation

File Structure

number-flow.tsx

Usage

import { NumberFlow } from '@/components/sora-ui/texts/number-flow';
import { useState } from 'react';

export default function Page() {
  const [value, setValue] = useState(1234.56);

  return (
    <NumberFlow
      value={value}
      format={{ style: 'currency', currency: 'USD' }}
    />
  );
}

Scroll-triggered count-up

Enable scrollTrigger to count up from 0 the first time the element scrolls into view — useful for landing-page stats sections:

<NumberFlow scrollTrigger value={12_500} suffix="+ users" />

Props

PropTypeDefault
value?
number
-
locales?
Intl.LocalesArgument
-
format?
Intl.NumberFormatOptions
-
prefix?
string
-
suffix?
string
-
trend?
number | ((prevValue: number, value: number) => number)
(prevValue, value) => Math.sign(value - prevValue)
transition?
Transition
{ duration: 0.9, ease: [0.16, 1, 0.3, 1] }
spinTransition?
Transition
-
respectMotionPreference?
boolean
true
willChange?
boolean
false
scrollTrigger?
boolean
false
once?
boolean
true
viewportMargin?
string
"0px 0px -10% 0px"
onAnimationsStart?
() => void
-
onAnimationsFinish?
() => void
-
className?
string
-

When to Use

Use NumberFlow for stats, KPIs, live counters, and pricing displays where a value updates over time and you want to draw attention to the change — dashboards, checkout totals, leaderboard scores, or animated metrics on a landing page.

It's not meant for large blocks of static numeric text; the animation overhead only pays off when the value actually changes at runtime.

Accessibility

The root element uses role="img" with an aria-label set to the fully formatted value (e.g. "$1,234.56"), so assistive technology always reads the current number as a single unit rather than a stream of individually-rolling digits, which are hidden from the accessibility tree via aria-hidden.

When prefers-reduced-motion: reduce is set, NumberFlow updates instantly with no animation by default (respectMotionPreference).

Credits

Inspired by Number Flow. Reimplemented for Motion and React.

The original is a framework-agnostic web component built in vanilla JS/CSS, with thin wrappers for React, Vue, and Svelte. This version is a ground-up port for the Sora registry: same core ideas — per-digit rolling faces, the continuous trend-loop, the edge mask — reimplemented with React state and Motion's motion/react (motion values, useTransform, AnimatePresence) in place of the original's custom element and CSS-driven animation.

Built by Axyl. A motion-first component registry for React.

Last updated: 7/6/2026