Animated Numbers
navdeep-singh/animated-numbersFreeComponent
Accessible in-view number counter with locale-aware formatting and reduced-motion support.
Install it
npx shadcn@latest add https://ui.navdeepsingh.dev/r/animated-numbers.jsonSource
1'use client'23import type { ComponentPropsWithoutRef } from 'react'4import { useEffect, useMemo, useRef } from 'react'5import {6 animate,7 motion,8 useInView,9 useMotionValue,10 useReducedMotion,11 useTransform,12} from 'motion/react'1314import { cn } from '@/lib/utils'1516export type AnimatedNumberProps = Omit<ComponentPropsWithoutRef<'span'>, 'children'> & {17 value: number18 from?: number19 prefix?: string20 suffix?: string21 decimalPlaces?: number22 duration?: number23 delay?: number24 locale?: string25}2627export function AnimatedNumber({28 value,29 from = 0,30 prefix = '',31 suffix = '',32 decimalPlaces = 0,33 duration = 1,34 delay = 0,35 locale = 'en-US',36 className,37 ...props38}: AnimatedNumberProps) {39 const ref = useRef<HTMLSpanElement>(null)40 const shouldReduceMotion = useReducedMotion()4142 const isInView = useInView(ref, {43 once: true,44 amount: 0.6,45 })4647 const animatedValue = useMotionValue(from)4849 const formatter = useMemo(50 () =>51 new Intl.NumberFormat(locale, {52 minimumFractionDigits: decimalPlaces,53 maximumFractionDigits: decimalPlaces,54 }),55 [decimalPlaces, locale],56 )5758 const formattedValue = useTransform(animatedValue, (currentValue) => {59 return `${prefix}${formatter.format(currentValue)}${suffix}`60 })6162 const accessibleValue = `${prefix}${formatter.format(value)}${suffix}`6364 useEffect(() => {65 if (shouldReduceMotion) {66 animatedValue.set(value)67 return68 }6970 if (!isInView) return7172 const controls = animate(animatedValue, value, {73 duration,74 delay,75 ease: [0.22, 1, 0.36, 1],76 })7778 return () => controls.stop()79 }, [animatedValue, delay, duration, isInView, shouldReduceMotion, value])8081 return (82 <span ref={ref} className={cn('inline-block tabular-nums', className)} {...props}>83 <motion.span aria-hidden>{formattedValue}</motion.span>84 <span className="sr-only">{accessibleValue}</span>85 </span>86 )87}8889export default AnimatedNumber
What it pulls in
npm packages
Files it writes
More from navdeep-singh
All 62 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Groupanimated-group | navdeep-singh | Components | Free | 1 dep | |
| Animated Tabsanimated-tabs | navdeep-singh | Components | Free | 2 deps | |
| Approval Panel Illustrationapproval-panel | navdeep-singh | Components | Free | 2 deps · 2 files | |
| Brand Logobrand-logo | navdeep-singh | Components | Free | 1 dep | |
| Designed for Focus Illustrationdesigned-for-focus-illustration | navdeep-singh | Components | Free | 1 dep | |
| Expandable Cardexpandable-card | navdeep-singh | Components | Free | 4 deps | |
| Fast by Default Illustrationfast-by-default-illustration | navdeep-singh | Components | Free | 1 dep | |
| Flexible at Scale Illustrationflexible-at-scale-illustration | navdeep-singh | Components | Free | 1 dep |
