@vectorvesper/motion/reactReact · Number Ticker

useNumberTicker

Animating numerical counters via React useState triggers up to 120 full component re-renders per second, degrading dashboard UI performance. useNumberTicker animates numbers smoothly on the shared FrameConductor by mutating DOM textContent directly with zero React re-renders.

The useNumberTicker hook eases numerical values to their targets by writing directly to the attached DOM node's textContent property inside the FrameConductor render lane.

The hook automatically sets font-variant-numeric: tabular-nums on the target element, ensuring numbers remain aligned without layout jitter as digit widths change.

Built on top of standard Intl.NumberFormat, the hook formats currencies, percentages, and locale-specific decimal separators seamlessly. When data values update mid-animation, the transition retargets smoothly without restarting from zero.

Zero-Re-Render Interactive Dashboard Counters

DIRECT DOM MUTATION
Demo loads on scroll

Quick start

Attach the returned ref to a span element. The hook handles interpolation, formatting, and DOM updates automatically.

Tabular numeric font styling is applied automatically to prevent layout width wobble.

Intl Formatting Recipes & Precision

Configure localized currencies, signed percentage metrics, and custom unit suffixes.

Format TypeConfiguration ExampleSample Output
Currency (USD){ format: { style: "currency", currency: "USD", maximumFractionDigits: 0 } }$428,500
Signed Percentage{ suffix: "%", format: { signDisplay: "exceptZero", minimumFractionDigits: 2 } }+3.42%
Latency / Units{ suffix: " ms", format: { maximumFractionDigits: 1 } }14.8 ms
European Locale{ locale: "de-DE", format: { maximumFractionDigits: 0 } }24.800

API Reference

Syntax

Interpolates a numeric value toward target numbers on the conductor render lane without React state re-renders.

Parameters

Parameters.fieldTypeDefaultDescription
valuenumber(none)The target numerical value to animate towards.
options.speednumber6Damping catch-up speed per second. Higher values reach target faster.
options.formatIntl.NumberFormatOptionsundefinedStandard Intl configuration for currencies, percentages, and decimal places.
options.localestringbrowserLocale string (e.g. 'en-US', 'de-DE') used for number localization.
options.prefixstring""Static string prepended to the formatted output (e.g. '+', '~').
options.suffixstring""Static string appended to the formatted output (e.g. '%', ' ms').

Return Value

{ ref: RefObject<T | null> }

Ref attached to the HTML text element.

Properties & State

Properties.fieldTypeDescription
refRefObject<T | null>DOM ref bound to the text element whose textContent is mutated.

Conductor Unsubscription Lifecycle

The hook subscribes to the FrameConductor render lane upon mount and unsubscribes cleanly on unmount.

1. Automatic TeardownReact Hook Lifecycle
2. Reduced Motion SafetyInstant Value Snap

Lifecycle & Invariant Guarantees

  • Zero React re-renders: Animation frames mutate textContent directly on the DOM node, preserving React fiber tree stability.
  • Tabular digits stability: Applies font-variant-numeric: tabular-nums to prevent character width jitter during transitions.
  • Frame-rate independence: Calculates exponential damping based on live delta-time, behaving identically at 60Hz, 120Hz, or 240Hz.
  • Dynamic retargeting: Smoothly shifts target destinations mid-flight without snapping or restarting from initial values.

Production Examples

Battle-tested production patterns ready to copy directly into your codebase.

Smoothly ease prices when users toggle between monthly and annual plans.

When NOT to use this

Financial accounting ledgers, medical dosages, or critical safety thresholds.
→ instead Render values directly. Intermediate interpolated digits represent inaccurate values during motion.
Values change faster than the damping convergence window (e.g. 60Hz streaming audio meters).
→ instead Render direct canvas meters or throttle incoming data stream frequency.
Displaying completely static numbers that never change after mount.
→ instead Render plain static JSX text nodes to avoid creating unnecessary frame subscriptions.

Rules & Gotchas

  • Separate application state from display presentation: Store the authoritative numeric value in application state; use the hook exclusively for visual transition smoothing.
  • Feed meaningful discrete state changes: Trigger updates on user interactions, toggle selections, or polled intervals rather than noisy continuous streams.
  • Avoid continuous screen reader announcements: Direct textContent updates provide standard accessibility; reserve aria-live alerts for discrete status updates.
  • Animate only visible viewport elements: On large data tables or dashboards, instantiate tickers only for currently visible rows.

Related Motion Components