labMagnetic Button

Magnetic Button

A button that leans toward the cursor on a spring.

Source

"use client";

import { motion, useReducedMotion, useSpring } from "motion/react";
import type { PointerEvent } from "react";

const spring = { stiffness: 300, damping: 20, mass: 0.5 };
const pull = 0.35;

export function MagneticButton() {
  const reduceMotion = useReducedMotion();
  const x = useSpring(0, spring);
  const y = useSpring(0, spring);

  function handlePointerMove(event: PointerEvent<HTMLButtonElement>) {
    if (reduceMotion) return;
    const rect = event.currentTarget.getBoundingClientRect();
    x.set((event.clientX - rect.left - rect.width / 2) * pull);
    y.set((event.clientY - rect.top - rect.height / 2) * pull);
  }

  function reset() {
    x.set(0);
    y.set(0);
  }

  return (
    <motion.button
      type="button"
      style={{ x, y }}
      onPointerMove={handlePointerMove}
      onPointerLeave={reset}
      whileTap={{ scale: 0.96 }}
      className="rounded-full bg-fg px-6 py-3 font-medium text-bg text-sm"
    >
      Hover me
    </motion.button>
  );
}