CSS · 300 ms
Magnetic hover
An element that pulls toward the cursor when nearby, snaps back when it leaves.
Listen for pointermove on the element. Compute the cursor's offset from the element centre and apply it as a transform — scaled down (e.g. 0.3) so the element follows but doesn't track 1:1. On pointerleave, transition back to zero. The factor (we use 0.35) is the whole game: 0.1 feels lifeless, 0.6 feels gimmicky. 0.35 reads as tactile.
by
udaysinh
Demo
Live demo
Move your cursor near the button — it follows at 35% of the offset.
The demo runs the same CSS code shown below — replay to retrigger.
Code
Pointermove handler — apply translate scaled to a fraction of the cursor offset.js
const el = document.querySelector('.magnetic');
const FACTOR = 0.35;
el.addEventListener('pointermove', (e) => {
const r = el.getBoundingClientRect();
const cx = r.left + r.width / 2;
const cy = r.top + r.height / 2;
const dx = (e.clientX - cx) * FACTOR;
const dy = (e.clientY - cy) * FACTOR;
el.style.transform = `translate(${dx}px, ${dy}px)`;
});
el.addEventListener('pointerleave', () => {
el.style.transform = 'translate(0, 0)';
});Spring back is just a transition — no JS needed for the return.css
.magnetic {
transition: transform 300ms cubic-bezier(0.2, 0.9, 0.2, 1);
}