Cards
MagneticCard
The card leans toward the pointer like a magnet, the content inside pulls a little further, and both spring back when the pointer leaves.
Download
- React
- Tailwind CSS v4
- motion
components/ui/magnetic-card.tsx
"use client";
import type { ReactNode } from "react";
import { motion, useMotionValue, useReducedMotion, useSpring } from "motion/react";
type MagneticCardProps = {
children: ReactNode;
className?: string;
/** How far the card follows the pointer, 0 to 1. */
strength?: number;
/** Extra pull on the content inside, so it feels like it floats in the card. */
depth?: number;
};
const SPRING = { stiffness: 180, damping: 16, mass: 0.6 };
/* MagneticCard: the card leans toward the pointer like a magnet and springs back when it leaves. */
export function MagneticCard({
children,
className = "rounded-2xl border border-white/10 bg-[#16132a] p-6 text-white",
strength = 0.15,
depth = 0.5,
}: MagneticCardProps) {
const reduce = useReducedMotion();
const dx = useMotionValue(0);
const dy = useMotionValue(0);
const x = useSpring(dx, SPRING);
const y = useSpring(dy, SPRING);
const ix = useSpring(0, SPRING);
const iy = useSpring(0, SPRING);
const onMove = (e: React.PointerEvent<HTMLDivElement>) => {
if (reduce) return;
const r = e.currentTarget.getBoundingClientRect();
const ox = e.clientX - (r.left + r.width / 2);
const oy = e.clientY - (r.top + r.height / 2);
dx.set(ox * strength);
dy.set(oy * strength);
ix.set(ox * strength * depth);
iy.set(oy * strength * depth);
};
const onLeave = () => {
dx.set(0);
dy.set(0);
ix.set(0);
iy.set(0);
};
return (
<motion.div onPointerMove={onMove} onPointerLeave={onLeave} style={{ x, y }} className={className}>
<motion.div style={{ x: ix, y: iy }}>{children}</motion.div>
</motion.div>
);
}
1. Install the dependency.
npm i motion2. Paste the Code tab into
components/ui/magnetic-card.tsx. The styles are Tailwind CSS v4 classes.3. Use it. This is the preview above:
app/magnetic-card-demo.tsx
import { MagneticCard } from "@/components/ui/magnetic-card"; export default function MagneticCardExample() { return ( <div className="grid h-full place-items-center bg-[#0b0a14] p-6"> <MagneticCard className="w-full max-w-[300px] rounded-2xl border border-white/10 bg-gradient-to-br from-[#221c3d] to-[#120f22] p-6 text-white"> <p className="font-mono text-[11px] uppercase tracking-[0.2em] text-[#a78bfa]">Workshop</p> <p className="mt-3 text-2xl font-semibold">Motion for designers</p> <p className="mt-2 text-sm text-white/60">Move your pointer over the card.</p> </MagneticCard> </div> ); }
Props
| Name | Type | Default | What it does |
|---|---|---|---|
| children | ReactNode | — | Card content. |
| strength | number | 0.15 | How far the card follows the pointer, 0 to 1. |
| depth | number | 0.5 | Extra pull on the content inside. |
| className | string | dark violet card | Replaces the default look. |