Counting Number

A number that counts up to its value, written straight to the DOM.

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

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

const run = ref(0)
const key = computed(() =>
  [run.value, props.number, props.fromNumber, props.padStart, props.decimalSeparator, props.decimalPlaces, props.delay].join(),
)
</script>

<template>
  <div class="flex flex-col items-center gap-6">
    <CountingNumber
      :key="key"
      :number="Number(number)"
      :from-number="Number(fromNumber)"
      :pad-start="padStart === true || padStart === 'true'"
      :decimal-separator="decimalSeparator"
      :decimal-places="Number(decimalPlaces)"
      :delay="Number(delay)"
      class="text-4xl font-semibold tabular-nums"
    />
    <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 { CountingNumber } from '@animate-ui/vue/primitives/texts/counting-number';
</script>

<template>
  <CountingNumber :number="2025" in-view />
</template>

A new number springs on from where the count is instead of restarting it.

Animation

  • Counts from from-number to number on a spring (stiffness: 90, damping: 50): most of the range goes by in the first second, then the last units tick in slowly (2025 lands after about 4.5s).
  • The ticking value is written to the DOM directly, without a Vue render per frame.
  • transition takes other spring options, or any Motion transition with a type or an ease.
  • <AnimateUIProvider :tempo> paces the default spring.
  • Under reduced motion, the number shows its target right away.
  • Screen readers read the target value once, never the ticking values.

API Reference

CountingNumber

PropTypeDefault
number
number-
from-number?
number0
pad-start?
booleanfalse
decimal-separator?
string'.'
thousand-separator?
string-
decimal-places?
number0
transition?
SpringOptions | Transition{ stiffness: 90, damping: 50 }
delay?
number0
initially-stable?
booleanfalse
in-view?
booleanfalse
in-view-margin?
string'0px'
in-view-once?
booleantrue
...props?
HTMLAttributes-

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

Last updated: 10/23/2026