Components
Starting preview...
Easily animate numbers.
@motion-primitives
npx shadcn@latest add https://21st.dev/r/ibelick/animated-number"use client";
import React, { useEffect, useRef, useState } from "react";
import { AnimatedNumber } from "@/components/ui/animated-number";
import { useInView } from "framer-motion";
import { Minus, Plus } from "lucide-react";
function AnimatedNumberBasic() {
const [value, setValue] = useState(0);
useEffect(() => {
setValue(2082);
}, []);
return (
<div className="flex w-full items-center justify-center">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
className="mr-3 h-3 w-3 fill-transparent stroke-black stroke-[1.3] dark:stroke-white"
>
<path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"></path>
</svg>
<AnimatedNumber
className="inline-flex items-center font-mono text-2xl font-light text-foreground"
springOptions={{
bounce: 0,
duration: 2000,
}}
value={value}
/>
</div>
);
}
function AnimatedNumberCounter() {
const [value, setValue] = useState(1000);
return (
<div className="flex w-full items-center justify-center space-x-2 text-foreground">
<button
aria-label="Decrement"
onClick={() => setValue((prev) => prev - 100)}
>
<Minus className="h-4 w-4" />
</button>
<AnimatedNumber
className="inline-flex items-center font-mono text-2xl font-light"
springOptions={{
bounce: 0,
duration: 1000,
}}
value={value}
/>
<button
aria-label="Increment"
onClick={() => setValue((prev) => prev + 100)}
>
<Plus className="h-4 w-4" />
</button>
</div>
);
}
function AnimatedNumberInView() {
const [value, setValue] = useState(0);
const ref = useRef(null);
const isInView = useInView(ref);
if (isInView && value === 0) {
setValue(10000);
}
return (
<div className="flex w-full items-center justify-center" ref={ref}>
<AnimatedNumber
className="inline-flex items-center font-mono text-2xl font-light text-foreground"
springOptions={{
bounce: 0,
duration: 10000,
}}
value={value}
/>
</div>
);
}
export default {
AnimatedNumberBasic,
AnimatedNumberCounter,
AnimatedNumberInView,
};