Animated Number
Smooth count-up/down number animation with formatting options.
<arc-animated-number> Overview
>
AnimatedNumber smoothly transitions between numeric values using `requestAnimationFrame` with an ease-out-expo curve, creating the classic "counting up" effect seen in dashboards, stat cards, and hero metrics. When the `value` attribute changes, the component interpolates from the current displayed number to the new target over the specified duration.
The ease-out-expo easing produces a fast start that decelerates toward the target, which feels natural and draws attention to the final number. Duration defaults to 1000ms but can be adjusted for different contexts — 500ms for small increments in real-time dashboards, 2000ms for dramatic hero reveals on landing pages.
Formatting is built in: `prefix` and `suffix` strings wrap the number (e.g. "$" and "K"), and `decimals` controls fixed decimal places. The `format` property switches between `number`, `currency`, and `percent` modes, each powered by `Intl.NumberFormat` for locale-aware formatting — thousands separators, decimal marks, and grouping all adapt to the configured `locale`. The default locale is `en-US`, but you can pass any BCP 47 tag (e.g. `de-DE`, `ja-JP`) for international formatting. The animation respects `prefers-reduced-motion` by snapping directly to the target value without animation.Guidelines
When to use
- Use in dashboard stat cards and hero metrics for visual impact
- Set decimals="2" for currency values and decimals="0" for counts
- Use prefix="$" or suffix="%" for contextual formatting
- Keep duration under 2000ms — longer animations feel sluggish
- Combine with ValueCard or Stat for complete metric displays
When not to use
- Do not animate more than 4-5 numbers simultaneously — it becomes distracting
- Do not use for rapidly changing real-time values — the animations will queue and feel laggy
- Do not set duration below 200ms — the animation becomes imperceptible
- Do not animate between extremely different magnitudes (1 to 1,000,000) — the counting is meaningless
- Do not use for static numbers that never change — add animation only when values update
Features
- Smooth count-up/down animation using requestAnimationFrame
- Ease-out-expo easing for natural deceleration
- Configurable duration from quick updates to dramatic reveals
- Prefix and suffix strings for currency, units, and labels
- Fixed decimal place control via decimals attribute
- Intl.NumberFormat-powered formatting with currency, percent, and number modes
- Configurable locale for international number formatting
- Respects `prefers-reduced-motion` by snapping to final value
Preview
Usage
<!-- Revenue counter -->
<arc-animated-number value="12847" prefix="$" duration="1500"></arc-animated-number>
<!-- Percentage with decimals -->
<arc-animated-number value="94.7" suffix="%" decimals="1"></arc-animated-number>
<!-- User count -->
<arc-animated-number value="3200" suffix=" users"></arc-animated-number> import { AnimatedNumber } from '@arclux/arc-ui-react';
function Dashboard({ revenue, percentage, users }) {
return (
<div>
<AnimatedNumber value={revenue} prefix="$" duration={1500} />
<AnimatedNumber value={percentage} suffix="%" decimals={1} />
<AnimatedNumber value={users} suffix=" users" />
</div>
);
} <script setup>
import { ref, onMounted } from 'vue';
import { AnimatedNumber } from '@arclux/arc-ui-vue';
const revenue = ref(0);
onMounted(() => { revenue.value = 12847; });
</script>
<template>
<AnimatedNumber :value="revenue" prefix="$" :duration="1500" />
</template> <script>
import { AnimatedNumber } from '@arclux/arc-ui-svelte';
import { onMount } from 'svelte';
let value = 0;
onMount(() => { value = 12847; });
</script>
<AnimatedNumber {value} prefix="$" duration={1500} /> import { Component, OnInit } from '@angular/core';
import { AnimatedNumber } from '@arclux/arc-ui-angular';
@Component({
imports: [AnimatedNumber],
template: `<arc-animated-number [value]="revenue" prefix="$" [duration]="1500" />`,
})
export class DashboardComponent implements OnInit {
revenue = 0;
ngOnInit() { this.revenue = 12847; }
} import { AnimatedNumber } from '@arclux/arc-ui-solid';
import { createSignal, onMount } from 'solid-js';
const [revenue, setRevenue] = createSignal(0);
onMount(() => setRevenue(12847));
<AnimatedNumber value={revenue()} prefix="$" duration={1500} /> import { AnimatedNumber } from '@arclux/arc-ui-preact';
import { useState, useEffect } from 'preact/hooks';
const [revenue, setRevenue] = useState(0);
useEffect(() => { setRevenue(12847); }, []);
<AnimatedNumber value={revenue} prefix="$" duration={1500} /> <!-- Auto-generated by @arclux/prism — do not edit manually -->
<!-- arc-animated-number — requires animated-number.css + tokens.css (or arc-ui.css) -->
<span class="arc-animated-number">
<span class="value"
role="status"
aria-live="polite"
>_format Value</span>
</span> <!-- Auto-generated by @arclux/prism — do not edit manually -->
<!-- arc-animated-number — self-contained, no external CSS needed -->
<span class="arc-animated-number" style="display: inline-block; font-family: 'JetBrains Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums">
<span style="white-space: nowrap"
role="status"
aria-live="polite"
>_format Value</span>
</span> API
-
valuenumber0 - Target number to animate to
-
durationnumber1000 - Animation duration in milliseconds
-
format'number' | 'currency' | 'percent''number' - Controls how the number is formatted using Intl.NumberFormat. Use currency with a prefix like $ or percent with a suffix like %.
-
prefixstring'' - String prepended before the number (e.g., "$")
-
suffixstring'' - String appended after the number (e.g., "%")
-
decimalsnumber0 - Number of fixed decimal places
-
localestring'en-US' - BCP 47 locale tag passed to Intl.NumberFormat for locale-aware number formatting (thousands separators, decimal marks).