Sparkles Text
Animated sparkle effects around text with configurable colors and density
animationtextsparkle
Install dependencies
$npm install framer-motionPreview
Source Code
"use client";
import { useEffect, useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
interface Sparkle {
id: string;
x: string;
y: string;
color: string;
delay: number;
size: number;
rotation: number;
}
interface SparklesTextProps {
children: React.ReactNode;
colors?: string[];
sparkleCount?: number;
className?: string;
}
function generateSparkle(colors: string[]): Sparkle {
return {
id: Math.random().toString(36).slice(2),
x: `${Math.random() * 120 - 10}%`,
y: `${Math.random() * 120 - 10}%`,
color: colors[Math.floor(Math.random() * colors.length)],
delay: Math.random() * 0.3,
size: Math.random() * 12 + 6,
rotation: Math.random() * 360,
};
}
export default function SparklesText({
children,
colors = ["#6366f1", "#8b5cf6", "#a78bfa", "#c4b5fd", "#e0e7ff"],
sparkleCount = 12,
className = "",
}: SparklesTextProps) {
const [sparkles, setSparkles] = useState<Sparkle[]>([]);
useEffect(() => {
const interval = setInterval(() => {
setSparkles((prev) => {
const next = [...prev, generateSparkle(colors)];
if (next.length > sparkleCount) next.shift();
return next;
});
}, 200);
return () => clearInterval(interval);
}, [colors, sparkleCount]);
return (
<span className={`relative inline-block ${className}`}>
<AnimatePresence>
{sparkles.map((sparkle) => (
<motion.svg
key={sparkle.id}
initial={{ opacity: 0, scale: 0, rotate: sparkle.rotation }}
animate={{
opacity: [0, 1, 1, 0],
scale: [0, 1.2, 1, 0],
rotate: sparkle.rotation + 180,
}}
exit={{ opacity: 0, scale: 0 }}
transition={{
duration: 1.2,
delay: sparkle.delay,
times: [0, 0.2, 0.7, 1],
}}
className="pointer-events-none absolute"
style={{
left: sparkle.x,
top: sparkle.y,
filter: `drop-shadow(0 0 ${sparkle.size / 2}px ${sparkle.color})`,
}}
width={sparkle.size}
height={sparkle.size}
viewBox="0 0 24 24"
fill={sparkle.color}
>
<path d="M12 0L14.59 9.41L24 12L14.59 14.59L12 24L9.41 14.59L0 12L9.41 9.41L12 0Z" />
</motion.svg>
))}
</AnimatePresence>
<strong className="relative z-10 bg-gradient-to-r from-indigo-400 via-purple-400 to-pink-400 bg-clip-text font-bold text-transparent">
{children}
</strong>
</span>
);
}