Tilt Card Glare
3D card with tilt and holographic glare effect that follows the cursor.
Last updated Mar 5, 2026
Component
Holographic Card
"use client";
import {
motion,
useMotionValue,
useTransform,
} from "framer-motion";
import { useCallback, useRef } from "react";
import { cn } from "@/lib/utils";
interface TiltCardGlareProps {
children: React.ReactNode;
className?: string;
glareClassName?: string;
glareColor?: string;
maxTilt?: number;
perspective?: number;
glareOpacity?: number;
glareIntensity?: number;
}
export function TiltCardGlare({
children,
className,
glareClassName,
glareColor = "rgba(255,255,255,0.8)",
maxTilt = 12,
perspective = 800,
glareOpacity = 0.4,
glareIntensity = 50,
}: TiltCardGlareProps) {
const ref = useRef<HTMLDivElement>(null);
const x = useMotionValue(0);
const y = useMotionValue(0);
const rotateX = useTransform(
y,
[-0.5, 0.5],
[maxTilt, -maxTilt],
);
const rotateY = useTransform(
x,
[-0.5, 0.5],
[-maxTilt, maxTilt],
);
const glareX = useTransform(
x,
[-0.5, 0.5],
[-glareIntensity, glareIntensity],
);
const glareY = useTransform(
y,
[-0.5, 0.5],
[-glareIntensity, glareIntensity],
);
const handleMouse = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
const rect = ref.current?.getBoundingClientRect();
if (!rect) {
return;
}
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
x.set((e.clientX - cx) / (rect.width / 2));
y.set((e.clientY - cy) / (rect.height / 2));
},
[x, y],
);
const handleMouseLeave = useCallback(() => {
x.set(0);
y.set(0);
}, [x, y]);
return (
<motion.div
ref={ref}
onMouseMove={handleMouse}
onMouseLeave={handleMouseLeave}
style={{
rotateX,
rotateY,
transformPerspective: perspective,
}}
className={cn("relative overflow-hidden", className)}
>
<motion.div
className={cn(
"pointer-events-none absolute inset-0",
glareClassName,
)}
style={{
background: `radial-gradient(circle at 50% 50%, ${glareColor} 0%, transparent 50%)`,
opacity: glareOpacity,
x: glareX,
y: glareY,
}}
/>
{children}
</motion.div>
);
}Installation
pnpm dlx shadcn@latest add "https://pulkitxm.com/components/tilt-card-glare.json"1. Install dependencies
pnpm add framer-motion2. Copy the component file
"use client";
import {
motion,
useMotionValue,
useTransform,
} from "framer-motion";
import { useCallback, useRef } from "react";
import { cn } from "@/lib/utils";
interface TiltCardGlareProps {
children: React.ReactNode;
className?: string;
glareClassName?: string;
glareColor?: string;
maxTilt?: number;
perspective?: number;
glareOpacity?: number;
glareIntensity?: number;
}
export function TiltCardGlare({
children,
className,
glareClassName,
glareColor = "rgba(255,255,255,0.8)",
maxTilt = 12,
perspective = 800,
glareOpacity = 0.4,
glareIntensity = 50,
}: TiltCardGlareProps) {
const ref = useRef<HTMLDivElement>(null);
const x = useMotionValue(0);
const y = useMotionValue(0);
const rotateX = useTransform(
y,
[-0.5, 0.5],
[maxTilt, -maxTilt],
);
const rotateY = useTransform(
x,
[-0.5, 0.5],
[-maxTilt, maxTilt],
);
const glareX = useTransform(
x,
[-0.5, 0.5],
[-glareIntensity, glareIntensity],
);
const glareY = useTransform(
y,
[-0.5, 0.5],
[-glareIntensity, glareIntensity],
);
const handleMouse = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
const rect = ref.current?.getBoundingClientRect();
if (!rect) {
return;
}
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
x.set((e.clientX - cx) / (rect.width / 2));
y.set((e.clientY - cy) / (rect.height / 2));
},
[x, y],
);
const handleMouseLeave = useCallback(() => {
x.set(0);
y.set(0);
}, [x, y]);
return (
<motion.div
ref={ref}
onMouseMove={handleMouse}
onMouseLeave={handleMouseLeave}
style={{
rotateX,
rotateY,
transformPerspective: perspective,
}}
className={cn("relative overflow-hidden", className)}
>
<motion.div
className={cn(
"pointer-events-none absolute inset-0",
glareClassName,
)}
style={{
background: `radial-gradient(circle at 50% 50%, ${glareColor} 0%, transparent 50%)`,
opacity: glareOpacity,
x: glareX,
y: glareY,
}}
/>
{children}
</motion.div>
);
}3. Import and use
import { TiltCardGlare } from "@/components/tilt-card-glare";
<TiltCardGlare className="rounded-2xl p-6">
Your content
</TiltCardGlare>;Usage
Import
Add the TiltCardGlare import.
import { TiltCardGlare } from "@/components/tilt-card-glare";Use
Wrap your card content.
<TiltCardGlare>Your content</TiltCardGlare>;Guidelines
- Wrap any card-like content. The component handles mouse tracking and transforms.
- maxTilt: rotation in degrees (default 12).
- perspective: CSS transform perspective (default 800).
- glareOpacity: 0–1. glareIntensity: how far the glare moves with cursor.
Props
All props are optional unless marked required. Use these to customize every aspect of the component.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | — | Card content (e.g. div, Card component). |
| className | string | — | Additional CSS classes for the wrapper. |
| glareClassName | string | — | Classes for the glare overlay. |
| glareColor | string | "rgba(255,255,255,0.8)" | Glare center color (CSS color, e.g. rgba(255,255,255,0.8) or amber tint). |
| maxTilt | number | 12 | Maximum tilt angle in degrees. |
| perspective | number | 800 | CSS transform perspective for 3D depth. |
| glareOpacity | number | 0.4 | Glare overlay opacity (0–1). |
| glareIntensity | number | 50 | How far the glare moves with cursor (pixels). |
Examples
Basic
Wrap your card content for 3D tilt and glare.
Holographic Card
import { TiltCardGlare } from "@/components/tilt-card-glare";
<TiltCardGlare className="h-48 w-72 rounded-2xl bg-linear-to-br from-indigo-600 to-pink-500">
<div className="flex h-full items-center justify-center p-6">
<span className="font-bold text-white">
Holographic Card
</span>
</div>
</TiltCardGlare>;Custom tilt
Increase maxTilt for more dramatic effect.
Holographic Card
import { TiltCardGlare } from "@/components/tilt-card-glare";
<TiltCardGlare
maxTilt={20}
className="rounded-xl border p-6"
>
<p>Card with stronger tilt</p>
</TiltCardGlare>;Glare customization
Adjust perspective, glare opacity and travel distance.
Holographic Card
import { TiltCardGlare } from "@/components/tilt-card-glare";
<TiltCardGlare
perspective={1200}
glareOpacity={0.6}
glareIntensity={80}
glareClassName="rounded-2xl"
>
<div className="p-6">Subtle 3D</div>
</TiltCardGlare>;Custom gradient & glare
Card gradient via className; glare color via glareColor.
Holographic Card
import { TiltCardGlare } from "@/components/tilt-card-glare";
<TiltCardGlare
className="h-48 rounded-2xl bg-linear-to-br from-amber-500 to-orange-600"
glareColor="rgba(255,255,255,0.5)"
>
<div className="flex h-full items-center justify-center p-6 text-white">
Warm card
</div>
</TiltCardGlare>;