← all components
#10

3D magnetic cards

Cards that tilt in 3D toward the cursor while a soft spotlight follows the pointer across the surface. The whole effect is CSS transforms driven by two CSS variables set from simple pointer math, so it stays smooth and needs no library.

ReactCSS3D
// LIVE DEMO
⚡
Fast
Ship in hours, not weeks
🎯
Precise
Pixel-perfect by default
✨
Premium
Feels expensive on touch
share this component →FacebookX / TwitterLinkedIn
// THE CODE
React
"use client";
import { useRef } from "react";

export function MagneticCard({ children }) {
  const ref = useRef(null);
  const onMove = (e) => {
    const el = ref.current, r = el.getBoundingClientRect();
    const px = (e.clientX - r.left) / r.width, py = (e.clientY - r.top) / r.height;
    el.style.setProperty("--rx", `${(0.5 - py) * 16}deg`);
    el.style.setProperty("--ry", `${(px - 0.5) * 16}deg`);
    el.style.setProperty("--mx", `${px * 100}%`);
    el.style.setProperty("--my", `${py * 100}%`);
  };
  const onLeave = () => {
    const el = ref.current;
    el.style.setProperty("--rx", "0deg"); el.style.setProperty("--ry", "0deg");
  };
  return (
    <div ref={ref} onPointerMove={onMove} onPointerLeave={onLeave}
      className="rounded-2xl p-6 w-[220px] select-none"
      style={{
        transform: "perspective(700px) rotateX(var(--rx,0)) rotateY(var(--ry,0))",
        transition: "transform .15s ease-out",
        background: "radial-gradient(240px circle at var(--mx,50%) var(--my,50%), rgba(56,189,248,.16), transparent 60%), linear-gradient(180deg,#12131f,#0c0d16)",
        border: "1px solid rgba(56,189,248,.18)",
        boxShadow: "0 20px 50px -24px rgba(56,189,248,.4)",
      }}>
      {children}
    </div>
  );
}
// HOW IT WORKS
  • 01The pointer position inside the card (0 to 1 on each axis) is mapped to rotateX and rotateY, so the card leans toward the cursor.
  • 02The same position is written to CSS variables --mx and --my, which drive a radial-gradient spotlight and a highlight overlay.
  • 03A short transition on transform smooths the tilt, and leaving the card resets the rotation to flat.
  • 04perspective() gives real depth, so the tilt reads as 3D rather than a flat skew.
Want a custom component for your product?
Let's build it →