✨
Glass Effect
🎨
Outline Style
🚀
Gradient Style
Hover to explore
💫
Interactive
Magnetic3D
Installation
Copy and paste the following code into your project.
components/ui/magnetic-card.tsx
"use client";
import React, { useRef, useEffect, useState } from "react";
import { cn } from "@/lib/utils";
export interface MagneticCardProps
extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
magneticStrength?: number;
rotationStrength?: number;
scaleOnHover?: number;
showMagneticField?: boolean;
fieldColor?: string;
darkFieldColor?: string;
}
export function MagneticCard({
children,
className,
magneticStrength = 0.5,
rotationStrength = 15,
scaleOnHover = 1.1,
showMagneticField = false,
fieldColor = "rgba(147, 51, 234, 0.15)",
darkFieldColor = "rgba(168, 85, 247, 0.25)",
...props
}: MagneticCardProps) {
const cardRef = useRef<HTMLDivElement>(null);
const [isHovered, setIsHovered] = useState(false);
const fieldRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const card = cardRef.current;
const field = fieldRef.current;
if (!card) return;
const handleMouseMove = (e: MouseEvent) => {
const { left, top, width, height } = card.getBoundingClientRect();
const centerX = left + width / 2;
const centerY = top + height / 2;
const mouseX = e.clientX;
const mouseY = e.clientY;
// Calculate distance from mouse to card center
const deltaX = mouseX - centerX;
const deltaY = mouseY - centerY;
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Calculate magnetic pull (stronger when closer)
const maxDistance = Math.max(window.innerWidth, window.innerHeight) / 2;
const pull = Math.max(0, 1 - distance / maxDistance);
// Calculate rotation based on mouse position
const rotateX = (deltaY / height) * rotationStrength;
const rotateY = -(deltaX / width) * rotationStrength;
// Apply transform with easing
const moveX = deltaX * pull * magneticStrength;
const moveY = deltaY * pull * magneticStrength;
const transform = `
translate(${moveX}px, ${moveY}px)
rotateX(${rotateX}deg)
rotateY(${rotateY}deg)
scale(${isHovered ? scaleOnHover : 1})
`;
card.style.transform = transform;
card.style.transition = "transform 0.3s cubic-bezier(0.23, 1, 0.32, 1)";
// Update magnetic field effect if enabled
if (showMagneticField && field) {
const fieldScale = 1 + pull * 0.5;
field.style.transform = `scale(${fieldScale})`;
field.style.opacity = (pull * 0.5).toString();
}
};
const handleMouseEnter = () => {
setIsHovered(true);
if (showMagneticField && field) {
field.style.opacity = "0.3";
}
};
const handleMouseLeave = () => {
setIsHovered(false);
card.style.transform = "translate(0, 0) rotateX(0) rotateY(0) scale(1)";
if (showMagneticField && field) {
field.style.transform = "scale(1)";
field.style.opacity = "0";
}
};
document.addEventListener("mousemove", handleMouseMove);
card.addEventListener("mouseenter", handleMouseEnter);
card.addEventListener("mouseleave", handleMouseLeave);
return () => {
document.removeEventListener("mousemove", handleMouseMove);
card.removeEventListener("mouseenter", handleMouseEnter);
card.removeEventListener("mouseleave", handleMouseLeave);
};
}, [
magneticStrength,
rotationStrength,
scaleOnHover,
isHovered,
showMagneticField,
]);
return (
<div className="relative" style={{ perspective: "1000px" }}>
{showMagneticField && (
<div
ref={fieldRef}
className="absolute inset-0 -z-10 rounded-[inherit] [--dark-field-color:var(--_dark-field-color)] dark:[--mode-field-color:var(--dark-field-color)]"
style={
{
background: `radial-gradient(circle at center, var(--field-color) 0%, transparent 70%)`,
transform: "scale(1.5)",
opacity: 0,
transition: "transform 0.3s ease, opacity 0.3s ease",
"--field-color": `var(--mode-field-color, ${fieldColor})`,
"--_dark-field-color": darkFieldColor,
} as React.CSSProperties
}
/>
)}
<div
ref={cardRef}
className={cn(
"relative rounded-lg bg-card text-card-foreground shadow-xs transition-all will-change-transform dark:shadow-lg dark:shadow-purple-500/5",
className,
)}
{...props}
>
{children}
</div>
</div>
);
}
Update the import paths to match your project setup.
import MagneticCard from "@/components/ui/magnetic-card";
Usage
import MagneticCard from "@/components/ui/magnetic-card";
export default function Example() {
return (
<MagneticCard
showMagneticField={true}
magneticStrength={0.4}
className="p-6"
>
<p>Card content</p>
</MagneticCard>
);
}
Props
Prop | Type | Description | Default |
---|---|---|---|
magneticStrength | number | Controls the strength of the magnetic effect (0-1) | 0.5 |
rotationStrength | number | Controls the degree of 3D rotation (0-45) | 15 |
scaleOnHover | number | Scale factor when hovering over the card | 1.1 |
showMagneticField | boolean | Shows a visual magnetic field effect | false |
fieldColor | string | Color of the magnetic field in light mode | rgba(147, 51, 234, 0.15) |
darkFieldColor | string | Color of the magnetic field in dark mode | rgba(168, 85, 247, 0.25) |
children | ReactNode | The content to be rendered inside the card | - |
className | string | Additional CSS classes to apply to the card | - |
Examples
Glass Effect Card
<MagneticCard
className="p-6 bg-white/80 dark:bg-white/10 backdrop-blur-xl border border-purple-200 dark:border-white/20 shadow-xl"
showMagneticField={true}
magneticStrength={0.4}
>
<p className="text-lg font-medium bg-clip-text text-transparent bg-linear-to-r from-purple-500 to-pink-500">
Glass Effect
</p>
</MagneticCard>
Outline Style Card
<MagneticCard
className="p-6 border-2 border-purple-500/30 dark:border-purple-400/30 bg-white/50 dark:bg-background/50"
showMagneticField={true}
magneticStrength={0.3}
rotationStrength={20}
>
<p className="text-lg font-medium text-purple-950 dark:text-purple-100">
Outline Style
</p>
</MagneticCard>
Gradient Style Card
<MagneticCard
className="p-6 bg-linear-to-br from-purple-500 to-pink-500 dark:from-purple-600 dark:to-pink-600 text-white"
showMagneticField={true}
fieldColor="rgba(236, 72, 153, 0.15)"
darkFieldColor="rgba(236, 72, 153, 0.25)"
scaleOnHover={1.15}
>
<p className="text-lg font-medium">Gradient Style</p>
</MagneticCard>
Interactive Card with Custom Content
<MagneticCard
className="overflow-hidden group bg-white dark:bg-card"
showMagneticField={true}
magneticStrength={0.5}
rotationStrength={12}
>
<div className="p-6 flex flex-col items-center gap-2">
<div className="text-2xl group-hover:scale-110 duration-300">💫</div>
<p className="text-lg font-medium text-purple-950 dark:text-purple-100">
Interactive
</p>
<div className="flex gap-2">
<span className="px-2 py-0.5 rounded-full text-xs bg-purple-100 dark:bg-purple-400/20 text-purple-700 dark:text-purple-300">
Magnetic
</span>
</div>
</div>
</MagneticCard>