Number Animation Number Ticker
beui/number-tickerFreeComponent
Slot-machine rolling digits with staggered entry.
Install it
npx shadcn@latest add https://beui.dev/r/number-ticker.jsonSource
1"use client";2// beui.dev/components/motion/number34import { animate, motion, useInView, useReducedMotion } from "motion/react";5import { useEffect, useMemo, useRef, useState } from "react";6import { EASE_OUT } from "@/lib/ease";7import { cn } from "@/lib/utils";89export interface NumberTickerProps {10 value: number;11 /** Digits to pad to (left). */12 pad?: number;13 /** Per-digit roll duration in seconds. */14 duration?: number;15 /** Stagger between digits. */16 stagger?: number;17 /** Render only after the element enters the viewport. */18 startOnView?: boolean;19 prefix?: string;20 suffix?: string;21 /** Add a small blur during digit rolls. */22 blur?: boolean;23 className?: string;24 digitClassName?: string;25 /** Insert locale group separators (commas). Server-component safe. */26 locale?: boolean;27 /** Custom formatter. Client-only — server components must use `locale` instead. */28 format?: (value: number) => string;29}3031const DIGIT_HEIGHT_EM = 1.1;32const DIGITS = Array.from({ length: 10 }, (_, n) => n);3334export function NumberTicker({35 value,36 pad,37 duration = 0.9,38 stagger = 0.04,39 startOnView = true,40 prefix,41 suffix,42 blur = false,43 className,44 digitClassName,45 locale,46 format,47}: NumberTickerProps) {48 const containerRef = useRef<HTMLSpanElement>(null);49 const inView = useInView(containerRef, { once: true, amount: 0.6 });50 const [armed, setArmed] = useState(!startOnView);5152 useEffect(() => {53 if (startOnView && inView) setArmed(true);54 }, [startOnView, inView]);5556 const text = useMemo(() => {57 const rounded = Math.round(value);58 const formatted = format59 ? format(rounded)60 : locale61 ? rounded.toLocaleString()62 : rounded.toString();63 return pad ? formatted.padStart(pad, "0") : formatted;64 }, [value, pad, format, locale]);65 const glyphs = useMemo(() => {66 const chars = text.split("");67 // Key by place value (position from the right): a changing digit keeps its68 // identity and rolls to the new value instead of remounting and replaying69 // from 0. Growing numbers add glyphs on the left without re-keying the70 // ones, tens, hundreds already on screen.71 return chars.map((char, i) => ({ char, id: `g-${chars.length - 1 - i}` }));72 }, [text]);73 const readableText = `${prefix ?? ""}${text}${suffix ?? ""}`;7475 // Stagger is an entrance flourish. Once the reveal has played, value76 // changes roll every digit immediately — a per-digit delay on live updates77 // reads as lag.78// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Action Swap Bluraction-swap-blur | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Cascadeaction-swap-cascade | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Rollaction-swap-roll | beui | Components | Free | 3 deps · 4 files | |
| Agent Activityagent-activity | beui | Components | Free | 4 deps · 9 files | |
| Agent Loading States Agent Progressagent-progress | beui | Components | Free | 3 deps · 3 files | |
| AI Sidebarai-sidebar | beui | Components | Free | 4 deps · 5 files | |
| Animated Badgeanimated-badge | beui | Components | Free | 4 deps · 3 files | |
| Number Animation Animated Numberanimated-number | beui | Components | Free | 3 deps · 3 files |
