beta

Number Ticker <mv-number-ticker>

Contador animado formateado con Intl (en-US por defecto: moneda, porcentaje, compacto, decimales) en dos modos: interpolación suave u odómetro giratorio; se vuelve a animar con cada cambio de valor, sin saltos de layout.

CategoríaTexto animado
TipoWeb Component (<mv-number-ticker>)
Estadobeta
Keywordscounter, count-up, odometer, stats, kpi, animated-number, slot

When to use

  • A KPI, price or stat should count up to its value when scrolled into view
  • A live-updating value needs an odometer-style roll with no layout shift
  • Currency, percent or compact numbers must animate with locale-aware formatting

Avoid when

  • A complete key-figures section is needed rather than a single number → use Stats instead
  • A signature dashboard number should burst into particles with up/down flashes → use Particle Counter instead
  • Dense data tables where many numbers would animate at once and distract

Instalación

node scripts/add.mjs number-ticker --out ./src/marvelous

Agente de IA con el servidor MCP de Marvelous UI: install_components({ slugs: ["number-ticker"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Archivos copiados (dependencias incluidas): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, core/observe.js, components/number-ticker/number-ticker.js, components/number-ticker/number-ticker.css.

Uso

Marcado de referencia: parte de él y personalízalo con atributos, data-* y variables CSS:

<div id="nt-demo" style="display:grid;gap:1.5rem;width:min(100%,48rem);margin-inline:auto">
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(10rem,1fr));gap:.75rem">
    <div style="padding:1rem 1.1rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-lg);background:var(--mv-surface)">
      <div style="font:700 2rem/1.1 var(--mv-font-display);letter-spacing:-.03em"><mv-number-ticker value="12840" prefix="+"></mv-number-ticker></div>
      <div style="margin-top:.25rem;font-size:.85rem;color:var(--mv-fg-muted)">customer teams</div>
    </div>
    <div style="padding:1rem 1.1rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-lg);background:var(--mv-surface)">
      <div style="font:700 2rem/1.1 var(--mv-font-display);letter-spacing:-.03em"><mv-number-ticker value="4.9" suffix="/5" delay="150"></mv-number-ticker></div>
      <div style="margin-top:.25rem;font-size:.85rem;color:var(--mv-fg-muted)">average rating</div>
    </div>
    <div style="padding:1rem 1.1rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-lg);background:var(--mv-surface)">
      <div style="font:700 2rem/1.1 var(--mv-font-display);letter-spacing:-.03em"><mv-number-ticker value="99.98" format="percent" delay="300" easing="var(--mv-ease-in-out)"></mv-number-ticker></div>
      <div style="margin-top:.25rem;font-size:.85rem;color:var(--mv-fg-muted)">uptime</div>
    </div>
    <div style="padding:1rem 1.1rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-lg);background:var(--mv-surface)">
      <div style="font:700 2rem/1.1 var(--mv-font-display);letter-spacing:-.03em"><mv-number-ticker value="2400000" format="currency" compact delay="450"></mv-number-ticker></div>
      <div style="margin-top:.25rem;font-size:.85rem;color:var(--mv-fg-muted)">raised in seed</div>
    </div>
  </div>

  <div style="display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:1rem;padding:1.25rem 1.4rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-xl);background:linear-gradient(to bottom,var(--mv-surface-raised),var(--mv-bg-subtle));box-shadow:var(--mv-shadow-sm)">
    <div>
      <div style="font-size:.8rem;letter-spacing:.08em;text-transform:uppercase;color:var(--mv-fg-muted)">Today’s revenue</div>
      <div style="margin-top:.2rem;font:800 clamp(2.2rem,6vw,3.4rem)/1.1 var(--mv-font-display);letter-spacing:-.04em">
        <mv-number-ticker id="nt-demo-live" mode="roll" value="48265.90" format="currency"></mv-number-ticker>
      </div>
    </div>
    <button class="mv-button" id="nt-demo-sale">+ Simulate a sale</button>
  </div>
</div>
<script type="module">
  const live = document.getElementById("nt-demo-live");
  document.getElementById("nt-demo-sale").addEventListener("click", () => {
    const next = Number(live.value) + Math.round(40 + Math.random() * 900) + Math.round(Math.random() * 99) / 100;
    live.value = next.toFixed(2);
  });
</script>

API

Attributes

NameTipoDefaultDescription
valuenumber0Target value. Changing it restarts the animation from the displayed value.
fromnumber0Starting value of the first animation.
modecount | rollcountcount = interpolation; roll = odometer (each digit rolls vertically).
formatdecimal | currency | percent | compactdecimalIntl style. percent expects percentage points (42 → 42%).
compactbooleanCompact notation, combinable (e.g. currency + compact → $2.4M).
currencyISO 4217 codeUSDCurrency for format=currency.
localeBCP 47en-USFormatting locale (separators, symbols).
decimalsnumber(inferred from value/from)Number of decimals shown.
durationnumber (ms)2000 (count) / 1400 (roll)Animation duration.
delaynumber (ms)0Delay before the first animation.
staggernumber (ms)60Offset between reels (roll mode).
easingCSS easingvar(--mv-ease-out)Any CSS curve, including var(--mv-ease-spring) (linear()).
triggerview | load | manualviewWhat starts the first animation. manual waits for replay().
prefix / suffixstringFixed text around the number (e.g. +, /5).

Methods

NameDescription
replay()Replays from from to value.

Events

NameDescription
mv-endAnimation finished (detail.value).

CSS variables

NameDefaultDescription
--mv-number-ticker-alignendAlignment of the number within its reserved width (count mode).
--mv-number-ticker-fade0.14emHeight of the top/bottom fade on the reels.

Accessibility

The final formatted value (prefix and suffix included) lives in a hidden copy; the animated digits are aria-hidden, so they are never read out in bursts. Tabular digits and reserved width: no jitter. With reduced motion, the final value shows immediately.

Esta página se tradujo con IA. Informar de un problema de traducción