This magnetic button effect creates a satisfying interaction where the button seems to 'stick' to the user's cursor as they hover over it. It calculates the distance between the mouse position and the button's center to apply a translation, giving it a physical, weighty feel. Perfect for primary calls-to-action.
npm install framer-motionimport { useRef, useState } from 'react';
import { motion } from 'framer-motion';
export default function MagneticButton() {
const ref = useRef<HTMLDivElement>(null);
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouse = (e: React.MouseEvent) => {
const { clientX, clientY } = e;
const { height, width, left, top } = ref.current!.getBoundingClientRect();
const middleX = clientX - (left + width / 2);
const middleY = clientY - (top + height / 2);
setPosition({ x: middleX, y: middleY });
}
const reset = () => {
setPosition({ x: 0, y: 0 });
}
const { x, y } = position;
return (
<motion.button
ref={ref}
animate={{ x, y }}
transition={{ type: "spring", stiffness: 150, damping: 15, mass: 0.1 }}
onMouseMove={handleMouse}
onMouseLeave={reset}
className="px-10 py-4 rounded-full bg-black text-white font-medium text-lg pointer-events-auto"
>
Hover Me
</motion.button>
)
}