Magnetic Button
A button whose label leans toward the cursor with a springy pull.
- Category
- Components
- Added
- 2026-08-01
- Deps
- 1
- Updated
- 2026-09-01
Props
"use client";
import { useRef, useState } from "react";
import { motion } from "framer-motion";
export function MagneticButton({
label = "Copy this",
strength = 24,
rounded = true,
variant = "red",
}: {
label?: string;
strength?: number;
rounded?: boolean;
variant?: "red" | "outline" | "dark";
}) {
const ref = useRef<HTMLButtonElement>(null);
const [pos, setPos] = useState({ x: 0, y: 0 });
function handleMove(e: React.MouseEvent<HTMLButtonElement>) {
const el = ref.current;
if (!el) return;
const rect = el.getBoundingClientRect();
const x = ((e.clientX - rect.left) / rect.width - 0.5) * strength;
const y = ((e.clientY - rect.top) / rect.height - 0.5) * strength;
setPos({ x, y });
}
const variantClasses =
variant === "red"
? "bg-red-500 text-white"
: variant === "outline"
? "border border-neutral-900 bg-transparent text-neutral-900"
: "bg-neutral-900 text-white";
return (
<button
ref={ref}
onMouseMove={handleMove}
onMouseLeave={() => setPos({ x: 0, y: 0 })}
className={
"relative px-8 py-4 font-semibold tracking-tight transition-colors " +
variantClasses +
(rounded ? " rounded-full" : " rounded-none")
}
>
<motion.span
animate={{ x: pos.x, y: pos.y }}
transition={{ type: "spring", stiffness: 150, damping: 12, mass: 0.4 }}
className="block"
>
{label}
</motion.span>
</button>
);
}
About this component
The pull toward the cursor turns a static pill button into something that feels alive under the mouse, computed from one measurement per mousemove: cursor position relative to the button's own bounding rect, remapped to a small offset, applied with a spring to the button's inner label — not the button itself. That's the detail worth noticing: only the motion.span moves, so the button's actual hit-box stays exactly where the eye expects it, and a click mid-drift still lands correctly. Reach for it over a plain CSS hover-scale on a small number of hero-level, high-intent CTAs; this library's Magnetic Nav Dock applies the same underlying idea to a whole row of icons instead of one label. The cost to know about: position tracking here goes through plain useState on every mousemove event, re-rendering the component on every pixel of movement — the dock and this library's cursor-follow blob both route raw pointer position through a Framer motion value instead specifically to avoid that, making this the more expensive of the two mouse-tracking patterns in the library, fine for one button, worth reconsidering for many.
Curator’s note
Curated & rebuilt in-house for viberdy — tuned spring values for a snappier feel than the common tutorial version.
Pairs well with
Matched on shared tags and category — the entries most likely to be used alongside this one.
Cursor Label Follower
componentsA contextual chip that trails the pointer and names whatever it is over.
Snapping Cursor
componentsA cursor dot that latches onto interactive elements and takes their exact shape.