Web Animations Easy
Magnetic Buttons
CTA buttons that pull toward the cursor with GSAP and snap back with an elastic ease on leave.
Open in Lab
MCP
html css gsap javascript
Targets: JS HTML
Code
[hidden] {
display: none !important;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
font-family: system-ui, sans-serif;
background: #0a0a0f;
color: #eee;
}
.stage {
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 2rem;
}
.stage h1 {
margin: 0 0 0.5rem;
font-size: 1.75rem;
}
.stage p {
margin: 0 0 2.5rem;
color: #888;
}
.actions {
display: flex;
flex-wrap: wrap;
gap: 1.25rem;
justify-content: center;
}
.magnet-wrap {
display: inline-block;
padding: 24px;
}
.magnet {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.9rem 1.75rem;
border-radius: 999px;
background: #7c5cff;
color: #fff;
text-decoration: none;
font-weight: 600;
will-change: transform;
}
.magnet--ghost {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.25);
color: #eee;
}const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
const strength = 0.35;
const max = 18;
document.querySelectorAll("[data-magnet]").forEach((btn) => {
const wrap = document.createElement("span");
wrap.className = "magnet-wrap";
btn.parentNode.insertBefore(wrap, btn);
wrap.append(btn);
if (reduced) return;
wrap.addEventListener("mousemove", (e) => {
const r = wrap.getBoundingClientRect();
const dx = e.clientX - (r.left + r.width / 2);
const dy = e.clientY - (r.top + r.height / 2);
const x = gsap.utils.clamp(-max, max, dx * strength);
const y = gsap.utils.clamp(-max, max, dy * strength);
gsap.to(btn, { x, y, duration: 0.35, ease: "power2.out" });
});
wrap.addEventListener("mouseleave", () => {
gsap.to(btn, { x: 0, y: 0, duration: 0.7, ease: "elastic.out(1, 0.45)" });
});
});<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Magnetic Buttons</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<main class="stage">
<h1>Move your cursor</h1>
<p>Buttons lean toward you, then spring back.</p>
<div class="actions">
<a href="#" class="magnet" data-magnet>Get started</a>
<a href="#" class="magnet magnet--ghost" data-magnet>View demo</a>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<script src="script.js"></script>
</body>
</html>Magnetic Buttons
Pointer distance maps to translate offsets inside a padded hit area — a small delight for primary CTAs.