Sliding Number

A number whose digits roll to their new value, like an odometer.

<script setup lang="ts">
import { RefreshIcon } from '@hugeicons/core-free-icons'
import { HugeiconsIcon } from '@hugeicons/vue'
import { SlidingNumber } from '@animate-ui/vue/primitives/texts/sliding-number'
import { ref } from 'vue'
import { Button } from '@/components/ui/button'

withDefaults(
  defineProps<{
    number?: number | string
    fromNumber?: boolean | string
    padStart?: boolean | string
    decimalSeparator?: string
    decimalPlaces?: number | string
    thousandSeparator?: string
    delay?: number | string
  }>(),
  {
    number: 2025,
    fromNumber: true,
    padStart: true,
    decimalSeparator: ',',
    decimalPlaces: 0,
    thousandSeparator: '.',
    delay: 0,
  },
)

const on = (value: boolean | string) => value === true || value === 'true'
const run = ref(0)
</script>

<template>
  <div class="flex flex-col items-center gap-6">
    <SlidingNumber
      :key="`${run}-${delay}-${fromNumber}`"
      :number="Number(number)"
      :from-number="on(fromNumber) ? 0 : undefined"
      :pad-start="on(padStart)"
      :decimal-separator="decimalSeparator"
      :decimal-places="Number(decimalPlaces)"
      :thousand-separator="thousandSeparator"
      :delay="Number(delay)"
      class="text-4xl font-semibold"
    />
    <Button variant="outline" size="sm" @click="run++">
      <HugeiconsIcon :icon="RefreshIcon" :stroke-width="2" data-icon="inline-start" />
      Replay
    </Button>
  </div>
</template>

Installation

npm install @animate-ui/vue motion-v
pnpm add @animate-ui/vue motion-v
yarn add @animate-ui/vue motion-v
bun add @animate-ui/vue motion-v

Usage

<script setup lang="ts">
import { SlidingNumber } from '@animate-ui/vue/primitives/texts/sliding-number';

defineProps<{ value: number }>();
</script>

<template>
  <SlidingNumber :number="value" thousand-separator="," />
</template>

Animation

  • Each digit sits on a wheel that springs to its new value (stiffness: 200, damping: 20, mass: 0.4), straight through the digits in between: going from 9 to 0, it rolls back through 8, 7…
  • With from-number, the number counts to number on a spring (stiffness: 90, damping: 50), every digit rolling on the way; a new number then counts on from the current value. Without it, the digits roll straight to their new value.
  • Digits are positioned in percentages of their own height: no measuring, right on the first frame and when the font size changes. Counting doesn't re-render Vue per frame.
  • <AnimateUIProvider :tempo> paces the default springs.
  • Under reduced motion, the digits change without rolling.
  • Screen readers read the number once, not every rolled digit.

API Reference

SlidingNumber

PropTypeDefault
number
number-
from-number?
number-
@number-change?
(number: number) => void-
pad-start?
booleanfalse
decimal-separator?
string'.'
decimal-places?
number0
thousand-separator?
string-
transition?
SpringOptions{ stiffness: 200, damping: 20, mass: 0.4 }
delay?
number0
initially-stable?
booleanfalse
in-view?
booleanfalse
in-view-margin?
string'0px'
in-view-once?
booleantrue
...props?
Omit<HTMLMotionProps<'span'>, 'children'>-

Built by Skyleen. The source code is available on GitHub.

Last updated: 10/23/2026