Spotlight Card
Card with a soft radial light that follows the cursor.
Edge-fast by default
Every page is pre-rendered and served from 300+ locations worldwide.
Secure from day one
SOC 2 controls, SSO and audit logs come standard on every plan.
components/ui/spotlight-card.tsx
"use client";
import { motion, useMotionTemplate, useMotionValue } from "motion/react";
import { Gauge, ShieldCheck } from "lucide-react";
import type { ReactNode } from "react";
type SpotlightCardProps = {
children: ReactNode;
className?: string;
/** Any CSS color for the glow */
color?: string;
};
export function SpotlightCard({ children, className = "", color = "rgba(37, 99, 235, 0.14)" }: SpotlightCardProps) {
const mouseX = useMotionValue(-400);
const mouseY = useMotionValue(-400);
const background = useMotionTemplate`radial-gradient(340px circle at ${mouseX}px ${mouseY}px, ${color}, transparent 75%)`;
return (
<div
onMouseMove={(e) => {
const rect = e.currentTarget.getBoundingClientRect();
mouseX.set(e.clientX - rect.left);
mouseY.set(e.clientY - rect.top);
}}
className={`group relative overflow-hidden rounded-2xl border border-zinc-200 bg-white p-7 transition-colors hover:border-zinc-300 ${className}`}
>
<motion.div
aria-hidden
className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100"
style={{ background }}
/>
<div className="relative">{children}</div>
</div>
);
}
export default function Demo() {
const items = [
{ icon: Gauge, title: "Edge-fast by default", text: "Every page is pre-rendered and served from 300+ locations worldwide." },
{ icon: ShieldCheck, title: "Secure from day one", text: "SOC 2 controls, SSO and audit logs come standard on every plan." },
];
return (
<div className="grid w-full max-w-3xl gap-4 sm:grid-cols-2">
{items.map(({ icon: Icon, title, text }) => (
<SpotlightCard key={title}>
<div className="grid size-10 place-items-center rounded-xl bg-blue-50 text-blue-600">
<Icon className="size-5" />
</div>
<h3 className="mt-5 font-semibold text-zinc-900">{title}</h3>
<p className="mt-2 text-sm leading-relaxed text-zinc-500">{text}</p>
</SpotlightCard>
))}
</div>
);
}
Installation
Install the dependencies
$ npm i motion lucide-reactCopy the source into
components/ui/spotlight-card.tsxcomponents/ui/spotlight-card.tsx"use client"; import { motion, useMotionTemplate, useMotionValue } from "motion/react"; import { Gauge, ShieldCheck } from "lucide-react"; import type { ReactNode } from "react"; type SpotlightCardProps = { children: ReactNode; className?: string; /** Any CSS color for the glow */ color?: string; }; export function SpotlightCard({ children, className = "", color = "rgba(37, 99, 235, 0.14)" }: SpotlightCardProps) { const mouseX = useMotionValue(-400); const mouseY = useMotionValue(-400); const background = useMotionTemplate`radial-gradient(340px circle at ${mouseX}px ${mouseY}px, ${color}, transparent 75%)`; return ( <div onMouseMove={(e) => { const rect = e.currentTarget.getBoundingClientRect(); mouseX.set(e.clientX - rect.left); mouseY.set(e.clientY - rect.top); }} className={`group relative overflow-hidden rounded-2xl border border-zinc-200 bg-white p-7 transition-colors hover:border-zinc-300 ${className}`} > <motion.div aria-hidden className="pointer-events-none absolute inset-0 opacity-0 transition-opacity duration-300 group-hover:opacity-100" style={{ background }} /> <div className="relative">{children}</div> </div> ); } export default function Demo() { const items = [ { icon: Gauge, title: "Edge-fast by default", text: "Every page is pre-rendered and served from 300+ locations worldwide." }, { icon: ShieldCheck, title: "Secure from day one", text: "SOC 2 controls, SSO and audit logs come standard on every plan." }, ]; return ( <div className="grid w-full max-w-3xl gap-4 sm:grid-cols-2"> {items.map(({ icon: Icon, title, text }) => ( <SpotlightCard key={title}> <div className="grid size-10 place-items-center rounded-xl bg-blue-50 text-blue-600"> <Icon className="size-5" /> </div> <h3 className="mt-5 font-semibold text-zinc-900">{title}</h3> <p className="mt-2 text-sm leading-relaxed text-zinc-500">{text}</p> </SpotlightCard> ))} </div> ); }Use it
The file exports the component and a
Demoshowing typical usage. Import whichever you need.