Animated number
A number that springs to its new value instead of jumping.
$
pnpm dlx shadcn@latest add https://lodeui.com/r/animated-number.json$12,840
components/examples/animated-number-demo.tsx
"use client";
import * as React from "react";
import { AnimatedNumber } from "@/components/ui/animated-number";
import { Button } from "@/components/ui/button";
export default function AnimatedNumberDemo() {
const [value, setValue] = React.useState(12840);
return (
<div className="flex flex-col items-center gap-5">
<AnimatedNumber value={value} format={(n) => `$${Math.round(n).toLocaleString("en-US")}`} className="text-5xl font-semibold tracking-tight" />
<div className="flex gap-2">
<Button variant="secondary" onClick={() => setValue((v) => Math.max(0, v - 2750))}>Refund</Button>
<Button onClick={() => setValue((v) => v + 4320)}>New sale</Button>
</div>
</div>
);
}When to use
- Totals and KPIs that change in response to input, like a price as seats change.
When not to use
- Values read precisely while changing quickly, like timers.
- When each digit should roll on its own: use the number ticker.
Installation
$
pnpm dlx shadcn@latest add https://lodeui.com/r/animated-number.json1Install the dependencies
npm install motion2Copy the source into your project
components/ui/animated-number.tsx"use client"; import * as React from "react"; import { motion, useSpring, useTransform } from "motion/react"; import { cn } from "@/lib/utils"; export interface AnimatedNumberProps { value: number; /** Formats the in-between values too, so keep it cheap. */ format?: (value: number) => string; className?: string; stiffness?: number; damping?: number; } const defaultFormat = (n: number) => Math.round(n).toLocaleString("en-US"); export function AnimatedNumber({ value, format = defaultFormat, className, stiffness = 140, damping = 24, }: AnimatedNumberProps) { const spring = useSpring(value, { stiffness, damping }); const display = useTransform(spring, (v) => format(v)); React.useEffect(() => { spring.set(value); }, [spring, value]); return ( <span className={cn("tabular-nums", className)}> {/* Screen readers get the settled value, not every frame. */} <span className="sr-only">{format(value)}</span> <motion.span aria-hidden>{display}</motion.span> </span> ); }
Usage
Import it from @/components/ui/animated-number after installing.
example.tsx
import { AnimatedNumber } from "@/components/ui/animated-number";
export function Total({ amount }: { amount: number }) {
return <AnimatedNumber value={amount} format={(n) => `$${Math.round(n).toLocaleString("en-US")}`} className="text-3xl font-semibold" />;
}API reference
AnimatedNumber
Springs from the previous value to the new one, formatting every frame.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | – | Target value. |
| format | (n: number) => string | en-US integer | Runs every frame, so keep it cheap. |
| stiffness / damping | number | 140 / 24 | Spring tuning. |
Accessibility
- Screen readers get the settled value from a visually hidden span; the animating text is aria-hidden.
Motion
- A spring drives the value; tabular numerals stop the width from jittering.
Responsive behavior
- Inline text; inherits size from its parent.
Performance
- Updates bypass React rendering: the motion value writes text directly.
Notes for AI
- Round inside format; the spring passes fractional values.
This page as Markdown, for assistants and coding agents:
/components/animated-number/markdownThe full library index for assistants is at /llms.txt.
Lode222 doc pagesllms.txt