8pt

Number Ticker

Number Ticker•Numbers
Overview

Each digit rolls to its target on its own, with tabular figures so nothing jitters. Click to roll again.

Plain HTML, CSS and a little vanilla JS, with no framework dependency. Copy the prompt into Claude Code, Cursor, Trae or Codex and the model adds Number Ticker to your project in your colors.

Where to use it

Data highlights, growth metrics, counters and stat cards.

Install

With Builder, install it with the 8pt CLI or call it directly from an editor connected to 8pt MCP.

$ npm i -g @8pt-dev/cli && 8pt add number-ticker
mcp › Use 8pt MCP to call get_component("number-ticker")

Code

Source for Number Ticker. Motion uses only transform and opacity and respects the Reduce motion setting.

<div class="x-tick">
  <div class="x-tick__num" data-value="2048"></div>
  <button class="x-tick__btn" type="button">Roll again</button>
</div>
.x-tick{display:grid;justify-items:center;gap:16px;color:var(--d-fg,#fff)}
.x-tick__num{display:flex;font:700 clamp(44px,7vw,72px)/1 var(--d-font,system-ui,sans-serif);font-variant-numeric:tabular-nums;letter-spacing:-.03em}
.x-tick__col{display:block;height:1.15em;overflow:hidden}
.x-tick__reel{display:flex;flex-direction:column;transition:transform 1.4s cubic-bezier(.16,1,.3,1)}
.x-tick__reel span{height:1.15em;line-height:1.15}
.x-tick__sep{width:.3em;text-align:center;opacity:.5}
.x-tick__btn{border:1px solid var(--d-line,rgba(255,255,255,.12));background:transparent;color:var(--d-muted,#a0a0ab);border-radius:999px;padding:7px 14px;font:500 12px/1 var(--d-font,system-ui,sans-serif);cursor:pointer;transition:transform .2s,opacity .2s}
.x-tick__btn:hover{color:var(--d-fg,#fff)}
.x-tick__btn:active{transform:scale(.96)}
const init = (root) => {
  const el = root.querySelector('.x-tick__num');
  const render = (v) => {
    const s = Number(v).toLocaleString('en-US');
    el.innerHTML = [...s].map(ch => ch === ',' ? '<span class="x-tick__sep">,</span>'
      : `<span class="x-tick__col"><span class="x-tick__reel">${'0123456789'.split('').map(n => `<span>${n}</span>`).join('')}</span></span>`).join('');
    const reels = el.querySelectorAll('.x-tick__reel'); const digits = s.replace(/,/g, '');
    requestAnimationFrame(() => requestAnimationFrame(() => reels.forEach((r, i) => {
      r.style.transitionDelay = (i * 60) + 'ms'; r.style.transform = `translateY(-${digits[i] * 10}%)`;
    })));
  };
  const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) { render(el.dataset.value); io.disconnect(); } });
…
Subscribe to Builder to see the full source.See pricing

More numbers components

View all

Progress Ring

More components

View all

AI Prompt Composer

Film Strip Carousel

Auto Tab Showcase

Media Bento Grid

Agent Chat Window

Model Pill Marquee

Director Art Cards

Mac File Window

Keep exploring