Number Counter Odometer Transition
A metric transition pattern that rolls fixed-width digit columns with translateY and tabular numerals so changing numbers feel continuous without resizing the row.
A metric transition pattern that rolls fixed-width digit columns with translateY and tabular numerals so changing numbers feel continuous without resizing the row.
Data-viz / number state / odometer
Three number transitions roll digit columns with transform so metric changes feel continuous without reflowing the label row.
Whole value · translateY
Translate one stacked value strip inside a fixed metric box.
Staggered columns
Stagger digit columns while preserving total metric width.
Rollover carry · window
Give the carry its own window instead of widening the text row.
A CSS odometer counter rolls fixed-width digit strips with translateY and tabular numerals so changing numbers never resize the metric row.
1<p class="metric" aria-live="polite"><span class="metric__label">Revenue</span><span class="metric__digits" aria-hidden="true"><span class="metric__slot"><span>3</span><span>3</span><span>3</span></span><span class="metric__slot"><span>4</span><span>4</span><span>4</span></span><span class="metric__slot"><span>5</span><span>6</span><span>7</span></span></span><span class="sr-only">Revenue changed to 347</span></p><style>.metric {display: inline-flex;align-items: center;gap: .75rem;16font-variant-numeric: tabular-nums;}.metric__digits {display: inline-flex;gap: .15rem;}.metric__slot {23width: 1ch;height: 1.4em;25overflow: hidden;display: grid;}.metric__slot > span {height: 1.4em;display: grid;place-items: center;animation: digit-roll 2.8s cubic-bezier(.45, 0, .2, 1) infinite;}@keyframes digit-roll {0%, 30% { transform: translateY(0); }60%, 100% { transform: translateY(-2.8em); }}.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }39@media (prefers-reduced-motion: reduce) {.metric__slot > span { animation: none; }}</style>
No. Hide decorative digit strips and announce the committed final value with a polite live region or visible text.
Proportional numerals have different widths, so a rolling counter can jitter even when the slot is fixed.
Swapping the whole number hides which digit changed. Fixed digit slots make 345 → 346 → 347 read as one controlled roll.
Reserve fixed digit slots and animate transform inside them. Do not animate raw text width.
A digit strip is only readable when the slot clips it. Without the window, 5, 6, and 7 leak into the same frame.
The strip contains multiple numbers stacked vertically. The slot clips it to one visible digit at a time.
Show the final number immediately while keeping the same fixed slots and accessible announcement.
An odometer counter rolls digits inside fixed slots. The animation is useful because it preserves metric width while making the value change perceptible. The reusable pattern is not a KPI card; it is the fixed-slot digit transition that prevents nearby labels, icons, or cards from shifting.
Use it for KPIs, counters, balances, score changes, and short metrics where the number is the subject and the update deserves attention. It works best when values change occasionally and the user benefits from seeing direction. Do not use it for long tables, rapidly updating telemetry, or logs where users need immediate legibility over motion.
Each digit column is an overflow: hidden slot. A vertical strip of digits moves with translateY, font-variant-numeric: tabular-nums keeps widths consistent, and the wrapper reserves the total metric footprint.
Never animate the text node width directly. That causes neighboring labels or cards to move, and the effect becomes more obvious when the new value has more digits. Also avoid announcing every intermediate digit; assistive tech should receive the final committed value, not the decorative roll.
Use aria-live politely for the committed value and hide decorative rolling strips if a separate accessible number is present. Reduced motion should snap to the final value while keeping the fixed slots and visible changed state. Do not make color or motion the only sign that a number increased or decreased.
An odometer counter is a fixed-slot transition, not a text-width animation. Each digit column reserves the width of the largest numeral and rolls a transform strip, so changing values do not resize the metric row.
Use tabular numbers and announce the final value once. Screen readers should not hear every intermediate digit in a roll. Reduced motion can snap to the new number while preserving the fixed slots and visible change state.
The pattern should be abstracted away from KPI cards. A KPI may use it, but the slug is about fixed digit columns, carry timing, overflow clipping, and stable metric width.
Watch sign, decimal, and unit changes separately. Digits can roll, but currency symbols, percent signs, separators, and labels should usually remain stable or crossfade without shifting the row.