Number Flow

Animates a number by rolling each digit to its new value.

Loading...

Anatomy

<NumberFlow.Root>
  <NumberFlow.Segments />
  <NumberFlow.HiddenValueText />
</NumberFlow.Root>

Segments renders one Digit per rolling digit and one Symbol per separator, currency sign, or literal. Each Digit renders a DigitTrack that holds a strip of DigitCells, and the strip is translated so the right cell lands in view. Pass a render function to Segments to compose the parts yourself:

<NumberFlow.Root>
  <NumberFlow.Segments>
    {(segment) =>
      segment.kind === 'digit' ? (
        <NumberFlow.Digit segment={segment}>
          <NumberFlow.DigitTrack segment={segment} />
        </NumberFlow.Digit>
      ) : (
        <NumberFlow.Symbol segment={segment} />
      )
    }
  </NumberFlow.Segments>
  <NumberFlow.HiddenValueText />
</NumberFlow.Root>

Examples

Basic

Pass a value and the number rolls to it whenever it changes. Use defaultValue instead to let the component own the value.

Formatting

formatOptions goes straight to Intl.NumberFormat, so currency, percent, compact notation, and precision all work as they would in Intl. Only the digits roll; signs, separators, and currency symbols swap in place.

Pricing

Switching between two prices is a common use. Set trend so every digit rolls in the direction the price moved.

Trend

The root carries data-trend (up, down, or none) for the whole roll, so the color can follow the direction of the last change.

Continuous

By default each digit takes its shortest path, so 9 to 0 rolls forward one step. Set continuous to spin through every value in between instead, which makes a jump from 120 to 245 read as counting rather than a cut.

Timing

spinTiming controls the digit roll and transformTiming controls digits entering and leaving. Both take CSS duration and easing values. Set stagger to delay each digit behind the one before it.

Locale

The number follows the locale from LocaleProvider, or the locale prop. Non-Latin numeral systems roll through their own glyphs, so ar-EG rolls through ٠ to ٩.

Prefix and Suffix

Use prefix and suffix for static text around the number. They never roll, and they are included in the accessible label.

Composition

Pass a function as the child of Segments to render each segment yourself. Each digit segment carries its decimal place (0 is the ones column, negative values are fraction digits), and each symbol carries its Intl type, so you can style the cents or the currency sign on their own. Segments keys every segment for you, so digits keep rolling when the number gains or loses a digit.

Live Announcements

Set live to announce changes to screen readers. The value is announced through HiddenValueText once the roll settles, so a fast counter is read once rather than for every intermediate value.

Root Provider

Use the useNumberFlow hook with RootProvider to read the value and call setValue from outside the component.

Guides

Styling

The component sets the structural styles inline: each digit is clipped to one line and the track is a vertical strip of 1lh cells. What is left is typography and color.

[data-number-flow-root] {
  font-variant-numeric: tabular-nums;
}

[data-number-flow-symbol] {
  white-space: pre;
}

[data-number-flow-digit] {
  vertical-align: top;
}

Use a font with tabular figures. Proportional digits change width as they roll, which makes the number jitter.

The root exposes data-state (idle or rolling), data-trend, and data-reduced-motion. Digits carry data-place, and symbols carry data-type with their Intl.NumberFormat part type, such as currency or group.

Accessibility

By default the root has role="img" and an aria-label with the formatted value, so assistive technology reads the number instead of the strip of cells. HiddenValueText is visually hidden and stays silent.

With live, the root drops its role and HiddenValueText becomes a polite status region that holds the settled value. Render HiddenValueText whenever you set live; without it, nothing is announced.

When the user prefers reduced motion, the number snaps to its new value. Set respectMotionPreference to false to roll anyway.

API Reference

Props

Root

Renders a <span> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
continuousfalse
boolean

Whether digits spin through every intermediate value instead of taking the nearest path.

defaultValue0
number

The initial value to render when uncontrolled.

formatOptions
NumberFormatOptions

The options to pass to the `Intl.NumberFormat` constructor.

id
string

The unique identifier of the machine.

ids
Partial<{ root: string; valueText: string }>

The ids of the elements in the number-flow. Useful for composition.

livefalse
boolean

Whether the value is announced to assistive technology as it changes. When `false`, the rendered value is still readable, but changes are not announced.

locale'en-US'
string

The current locale. Based on the BCP 47 definition.

onAnimationComplete
(details: AnimationDetails) => void

Callback fired when the roll animation settles.

onAnimationStart
(details: AnimationDetails) => void

Callback fired when a value change starts a roll animation.

onValueChange
(details: ValueChangeDetails) => void

Callback fired when the value changes.

prefix
string

A static string rendered before the formatted value. Does not animate.

render
ReactElement<unknown, string | JSXElementConstructor<any>> | RenderFn<EmptyState>

Render the part as a custom element, combining their props and behavior. Pass an element to have the part's props merged into it, or a function to control the merge yourself and read the part's state.

respectMotionPreferencetrue
boolean

Whether to suppress the roll animation when the user prefers reduced motion.

spinTiming{ duration: '900ms', easing: 'cubic-bezier(0.4, 0, 0.2, 1)' }
TimingOptions

The timing of the per-digit roll transition.

staggerundefined
string

A CSS `<time>` delay applied between adjacent digits, e.g. `"25ms"`.

suffix
string

A static string rendered after the formatted value. Does not animate.

transformTiming{ duration: '500ms', easing: 'cubic-bezier(0.4, 0, 0.2, 1)' }
TimingOptions

The timing of layout transitions - segments entering/exiting.

trendfalse
Trend

Controls the roll direction of each digit. - `false` (default): each digit takes its own shortest path (`9 -> 0` rolls forward one step). - `true`: every digit rolls in the direction of the overall value change. - `1` / `-1`: force every digit to roll up or down, regardless of the value change.

value
number

The controlled numeric value to render.

AttributeDescription
[data-number-flow-root]<uid>
[data-state]"rolling" | "idle"
[data-trend]
[data-reduced-motion]
CSS VariableDescription
--spin-durationThe spin duration value for the root
--spin-easingThe spin easing value for the root
--transform-durationThe transform duration value for the root
--transform-easingThe transform easing value for the root
--staggerThe stagger value for the root
--place-indexThe place index value for the root

DigitCell

Renders a <span> element.

PropDefaultType
cell
DigitCell

segment
DigitSegment

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
render
ReactElement<unknown, string | JSXElementConstructor<any>> | RenderFn<EmptyState>

Render the part as a custom element, combining their props and behavior. Pass an element to have the part's props merged into it, or a function to control the merge yourself and read the part's state.

AttributeDescription
[data-number-flow-digit-cell]<uid>
[data-place]
[data-digit]

Digit

Renders a <span> element.

PropDefaultType
segment
DigitSegment

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
render
ReactElement<unknown, string | JSXElementConstructor<any>> | RenderFn<EmptyState>

Render the part as a custom element, combining their props and behavior. Pass an element to have the part's props merged into it, or a function to control the merge yourself and read the part's state.

AttributeDescription
[data-number-flow-digit]<uid>
[data-place]

DigitTrack

Renders a <span> element.

PropDefaultType
segment
DigitSegment

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
render
ReactElement<unknown, string | JSXElementConstructor<any>> | RenderFn<EmptyState>

Render the part as a custom element, combining their props and behavior. Pass an element to have the part's props merged into it, or a function to control the merge yourself and read the part's state.

AttributeDescription
[data-number-flow-digit-track]<uid>
[data-place]

RootProvider

Renders a <span> element.

PropDefaultType
value
UseNumberFlowReturn

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
render
ReactElement<unknown, string | JSXElementConstructor<any>> | RenderFn<EmptyState>

Render the part as a custom element, combining their props and behavior. Pass an element to have the part's props merged into it, or a function to control the merge yourself and read the part's state.

Symbol

Renders a <span> element.

PropDefaultType
segment
SymbolSegment

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
render
ReactElement<unknown, string | JSXElementConstructor<any>> | RenderFn<EmptyState>

Render the part as a custom element, combining their props and behavior. Pass an element to have the part's props merged into it, or a function to control the merge yourself and read the part's state.

AttributeDescription
[data-number-flow-symbol]<uid>
[data-type]The type of the item

HiddenValueText

Renders a <span> element.

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
render
ReactElement<unknown, string | JSXElementConstructor<any>> | RenderFn<EmptyState>

Render the part as a custom element, combining their props and behavior. Pass an element to have the part's props merged into it, or a function to control the merge yourself and read the part's state.