Neon Card
Neon Card
Hover and move your cursor to see the magic ✨
Neon Card
Experience smooth animations ⚡
Installation
1
Install the following packages if you do not have it.
npm i framer-motion lucide-react
2
Copy and paste the following code into your project.
"use client";
import React, { useEffect, useRef, useState } from "react";
import { useTheme } from "next-themes";
import { motion, AnimatePresence } from "framer-motion";
interface NeonCardProps {
children: React.ReactNode;
className?: string;
gradientColors?: string[];
glowIntensity?: number;
}
const NeonCard = ({
children,
className = "",
gradientColors = ["#FF0080", "#7928CA", "#FF0080"],
glowIntensity = 0.5,
}: NeonCardProps) => {
const { theme } = useTheme();
const divRef = useRef<HTMLDivElement>(null);
const [position, setPosition] = useState({ x: 0, y: 0 });
const [isHovered, setIsHovered] = useState(false);
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!divRef.current) return;
const rect = divRef.current.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
setPosition({ x, y });
};
const getRandomPosition = () => {
if (!divRef.current) return { x: 0, y: 0 };
const bounds = divRef.current.getBoundingClientRect();
return {
x: Math.random() * bounds.width,
y: Math.random() * bounds.height,
};
};
if (!mounted) return null;
return (
<motion.div
ref={divRef}
onMouseMove={handleMouseMove}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className={`group relative rounded-2xl p-[2px] transition-all duration-500 hover:scale-[1.02] ${className}`}
style={{
background: `linear-gradient(90deg, ${gradientColors.join(", ")})`,
backgroundSize: "200% 100%",
animation: "shimmer 2s linear infinite",
boxShadow: `0 0 20px 2px rgba(${gradientColors[0]}15, ${glowIntensity})`,
}}
>
<div
className="absolute -inset-[1px] rounded-2xl opacity-75 blur-xl transition-all duration-500 group-hover:opacity-100"
style={{
background: `radial-gradient(1000px circle at ${position.x}px ${position.y}px, ${gradientColors[0]}15, transparent 40%)`,
}}
/>
<div
className="relative h-full w-full rounded-2xl border border-white/10 bg-slate-900/[0.85] p-8 transition-all duration-500 group-hover:bg-slate-900/70"
style={{
backdropFilter: "blur(12px)",
WebkitBackdropFilter: "blur(12px)",
}}
>
<div
className="pointer-events-none absolute inset-0 rounded-2xl opacity-0 transition-opacity duration-500 group-hover:opacity-100"
style={{
background: `
radial-gradient(800px circle at ${position.x}px ${position.y}px,
rgba(255,255,255,0.08),
transparent 40%
)
`,
}}
/>
<AnimatePresence>
{isHovered && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="absolute inset-0 overflow-hidden rounded-2xl pointer-events-none"
>
{[...Array(10)].map((_, i) => {
const startPos = getRandomPosition();
const endPos = getRandomPosition();
return (
<motion.div
key={i}
className="absolute h-2 w-2 rounded-full"
style={{
background: gradientColors[i % gradientColors.length],
boxShadow: `0 0 15px 2px ${gradientColors[i % gradientColors.length]
}`,
}}
initial={{
x: startPos.x,
y: startPos.y,
scale: 0,
opacity: 0,
}}
animate={{
x: endPos.x,
y: endPos.y,
scale: [0, 1, 0],
opacity: [0, 1, 0],
}}
transition={{
duration: 3,
repeat: Infinity,
delay: i * 0.2,
ease: "easeInOut",
}}
/>
);
})}
</motion.div>
)}
</AnimatePresence>
<div className="relative z-10 h-full">{children}</div>
</div>
<style jsx global>{`
@keyframes shimmer {
from {
background-position: 0% 50%;
}
to {
background-position: 200% 50%;
}
}
`}</style>
</motion.div>
);
};
export default function NeonCardDemo({ info }) {
return (
<div className="flex h-[500px] w-full flex-col gap-6 p-8 lg:h-[250px] lg:flex-row">
{info.map((item: any , key: number) => {
return (
<NeonCard
className="flex-1"
gradientColors={item.gradientColors}
glowIntensity={item.glowIntensity}
key={item.id}
>
<div className="flex h-full flex-col items-center justify-center space-y-4">
<span className={`bg-gradient-to-r ${item.titleColor} bg-clip-text text-5xl font-bold text-transparent drop-shadow-lg`}>
{item.title}
</span>
<p className="text-center text-sm font-medium text-gray-300/90">
{item.content}
</p>
</div>
</NeonCard>
)
})}
</div>
);
}
3