Number Ticker
ProAnimated 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.
import { SvNumberTickerComponent } from '@styloviz-pro/layout';Demo & usage
Basic usage
ProUsage example — open the gallery for the full interactive demo.
An interactive demo for this component lives in the gallery.
Open live demoMore examples
Count up on scroll
ProOdometer reels (PRO+)
ProScramble (PRO+)
ProCurrency formatting (PRO+)
ProAuto-fit a large value
ProThe same format in a table cell — no animation
ProThe ticker formats through svFormatTickerDisplay; the pipe is that function, for cells that must not animate.
A live metric that updates every few hundred ms
ProNo data is not zero
ProWhen 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
| Name | Type | Default | Description |
|---|---|---|---|
| loading | boolean | false | True while the figure is being fetched. |
| value | number | null | 0 | Target 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`. |
| invalidPlaceholder | string | SV_TICKER_INVALID_PLACEHOLDER | Shown in place of a value that is not a finite number. |
| invalidLabel | string | 'No value' | Read to assistive tech in place of a value that is not a finite number. |
| announce | NumberTickerAnnounce | 'polite' | Whether the settled value is announced (`polite`) or not (`off`). The animating digits are never announced, whatever this says. |
| updatePolicy | NumberTickerUpdatePolicy | '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. |
| from | number | 0 | Starting value. |
| duration | number | 1500 | Animation duration in milliseconds. |
| easing | NumberTickerEasing | 'ease-out' | Easing function. |
| variant | NumberTickerVariant | 'count' | Visual style of the animation. |
| format | NumberTickerFormat | 'plain' | Number formatting mode. |
| currency | string | 'USD' | ISO 4217 currency code (used when `format='currency'`). |
| locale | string | 'en-US' | BCP-47 locale (used when `format='currency'`). |
| prefix | string | '' | String prepended to the number (e.g. '$'). |
| suffix | string | '' | String appended to the number (e.g. '%', 'K'). |
| decimals | number | 0 | Number of decimal places. |
| separator | string | ',' | Thousands separator character (plain mode). |
| startOnView | boolean | true | Start animation only when element scrolls into view. |
| delay | number | 0 | Delay 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. |
| fit | boolean | true | Auto-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. |
| minFontScale | number | 0.4 | Lower bound for auto-fit scaling (fraction of the base font size). |
Outputs
| Event | Payload type | Description |
|---|---|---|
| animationStart | void | Emitted when the count-up animation starts. |
| animationComplete | void | Emitted 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.