Number Ticker

Pro

Animated count-up display with easing functions, IntersectionObserver start-on-view, prefix/suffix, thousands separator, decimal precision, auto-fit (scales down so large values never overflow) and reduced-motion support. Includes premium `odometer` (rolling reels), `scramble`, and `currency` (Intl) variants.

</>sv-number-ticker counteranimationmetricodometercurrency
import { SvNumberTickerComponent } from '@styloviz-pro/layout';

Demo & usage

Basic usage

Pro

Usage example — open the gallery for the full interactive demo.

Pro

An interactive demo for this component lives in the gallery.

Open live demo

More examples

Count up on scroll

Pro

Odometer reels (PRO+)

Pro

Scramble (PRO+)

Pro

Currency formatting (PRO+)

Pro

Auto-fit a large value

Pro

The same format in a table cell — no animation

Pro

The ticker formats through svFormatTickerDisplay; the pipe is that function, for cells that must not animate.

A live metric that updates every few hundred ms

Pro

No data is not zero

Pro

When to use

  • Drawing attention to a metric with an animated count-up (stats, hero numbers, results).
  • Landing pages and dashboards where a number reveal adds polish.
  • For continuously updating live values, use a Live Chart or bound text.

Async states

  • loading

Inputs

NameTypeDefaultDescription
loadingbooleanfalseTrue while the figure is being fetched.
valuenumber | null0Target value to animate to. `NaN`, `±Infinity` and `null` are not numbers and render `invalidPlaceholder` rather than `"NaN"` or a fake `0`. Accepts `null`, but READS as `number`: `null` is mapped to `NaN` (already the invalid state), so host code calling `ticker.value()` keeps a `number`.
invalidPlaceholderstringSV_TICKER_INVALID_PLACEHOLDERShown in place of a value that is not a finite number.
invalidLabelstring'No value'Read to assistive tech in place of a value that is not a finite number.
announceNumberTickerAnnounce'polite'Whether the settled value is announced (`polite`) or not (`off`). The animating digits are never announced, whatever this says.
updatePolicyNumberTickerUpdatePolicy'retarget'What a new `value` does after the first one has been shown. `restart` RESTARTS FOREVER. A metric updated every 200 ms with a 1500 ms count restarts from `from` on every update and never displays a stable number. `retarget` (the default) animates from what is on screen and never beyond the end of an animation already running, so a burst of updates lands on the latest value on schedule; `snap` skips the animation.
fromnumber0Starting value.
durationnumber1500Animation duration in milliseconds.
easingNumberTickerEasing'ease-out'Easing function.
variantNumberTickerVariant'count'Visual style of the animation.
formatNumberTickerFormat'plain'Number formatting mode.
currencystring'USD'ISO 4217 currency code (used when `format='currency'`).
localestring'en-US'BCP-47 locale (used when `format='currency'`).
prefixstring''String prepended to the number (e.g. '$').
suffixstring''String appended to the number (e.g. '%', 'K').
decimalsnumber0Number of decimal places.
separatorstring','Thousands separator character (plain mode).
startOnViewbooleantrueStart animation only when element scrolls into view.
delaynumber0Delay before the first animation starts (ms). A new `value` arriving while the delay is still pending does NOT skip it: the pending start simply counts to the latest value once the delay elapses (a non-number still shows the placeholder at once). Later updates follow `updatePolicy`; `restart` waits for the delay again.
fitbooleantrueAuto-fit the digits to the available width so a large value never overflows its wrapper (or the viewport). Measures the widest value against the container's real content box — the parent's horizontal padding and border are subtracted from the budget — and scales the font down (keeping a small margin) only when it would otherwise clip.
minFontScalenumber0.4Lower bound for auto-fit scaling (fraction of the base font size).

Outputs

EventPayload typeDescription
animationStartvoidEmitted when the count-up animation starts.
animationCompletevoidEmitted when the count-up animation completes.

Customization & theming

  • Animate to `value` from `from` over a `duration` with a chosen `easing`.
  • Formatting is a separate pure API: `svFormatTickerDisplay(value, options)`, `svFormatTickerNumber` and the `svTickerNumber` pipe (`SvTickerNumberPipe`) take the same options as the component's inputs, and the component formats through them.
  • Updates: `updatePolicy` — `retarget` (default) animates from the displayed value and never beyond the end of an animation already in flight, so a burst of updates settles on the latest value on schedule; `snap` shows updates immediately; `restart` counts from `from` every time (the old behaviour, which never settles under frequent updates).
  • Invalid numbers: `NaN`, `±Infinity` and `null` render `invalidPlaceholder` (default en dash) with no prefix or suffix, and are announced as `invalidLabel` (default "No value") — never "NaN" or a fake 0.
  • Measurement (X-4): automatic — auto-fit observes the parent through the core `svElementSize` primitive (one reading per frame, disconnected on destroy, nothing on the server) and re-fits whenever it resizes; where there is no `ResizeObserver` it falls back to viewport resizes. There is no manual measure call; a ticker inside a container that is hidden at init measures 0 and fits the moment the container is laid out.
  • Layout (X-9): not applicable — the ticker is inline content in normal flow; nothing is portalled, no scroll root is listened to (start-on-view uses an IntersectionObserver against the viewport), and no containing block or breakpoint matters. Auto-fit sizes against the parent's content box, so keep `min-w-0` on a grid or flex parent that must be able to shrink below the number.
  • `delay` applies to the first count; a new `value` arriving while it is still pending does not skip it — the pending start counts to the latest value when the delay elapses.
  • `value` accepts `null` but reads as a `number`: `null` is mapped to `NaN`, which renders the invalid placeholder.
  • Variant axes: `variant` (count, odometer, scramble) and `format` (plain, currency) are appearance; `startOnView`, `fit`, `updatePolicy` and `announce` are behavioural modes that combine with every variant.
  • Browser limits: without IntersectionObserver (SSR, very old engines) the count runs immediately; without requestAnimationFrame it snaps to the value; `format="currency"` depends on the runtime's Intl data and falls back to plain digits for an unknown currency or locale.
  • Pick a `variant`: `count` (default), `odometer` rolling reels, or `scramble`.
  • Format with `prefix`, `suffix`, `decimals` and `separator`, or set `format="currency"` with `currency` + `locale`.
  • Start on scroll into view with `startOnView` and a `delay`.
  • Auto-fit is on by default so big values never overflow — it sizes against the container content box (parent padding is subtracted), bound it with `minFontScale` or disable via `[fit]="false"`.

Best practices

  • Do: Trigger with `startOnView` so the animation plays when the number is visible.
  • Do: Keep the final value as readable text for assistive tech (handled).
  • Tip: Reduced motion is automatic: under `prefers-reduced-motion` the ticker shows the final value without counting — no extra configuration.
  • Don't: Don't animate a cached or daily figure without saying so. A number counting up reads as live, real-time precision; a cached total animated on every visit misleads. Put an "as of" time beside it, or use the `svTickerNumber` pipe, which never animates.
  • Do: Use `announce="off"` for a figure that updates constantly, so assistive tech is not interrupted on every settle.

Accessibility

  • Final value is real text in the `aria-label`, readable by assistive tech (uses the formatted value).
  • One announcement per value: the animating digits are `aria-hidden`, and the live region carries only the SETTLED value, updated when an animation lands — never per frame. `announce="off"` silences it while keeping the value readable.
  • Animation is skipped and the value snaps when reduced-motion is requested — including the odometer reels.
  • Emits `animationStart` and `animationComplete` around the count.

Feedback on Number Ticker

Spotted a gap in this page, or something that didn't work as described? Comments are GitHub Discussions in the public styloviz/community repo, so posting needs a GitHub account.

Loads giscus.app and GitHub — nothing is fetched until you click.