2.8 · Animation

Magnetic /
Custom Cursor.

Hide the native cursor. Replace with a smooth dot that grows when it hovers anything interactive — and magnetically pulls the CTA toward it. Awwwards staple.

What it is

A custom cursor is a JavaScript-controlled element that follows the mouse and replaces the native arrow. It can change size, color, and label depending on what it's hovering. The "magnetic" variant goes further: when the cursor enters certain interactive elements (CTAs, links), it snaps to them and pulls them slightly toward the actual cursor position, creating a tactile gravity-like feel.

How it works

Set cursor: none on the container. Create an absolutely-positioned element (the custom cursor). On mousemove, update its transform: translate(x, y). For smooth following, lerp toward the target position each animation frame. On mouseenter of any interactive element (with a data attribute like data-cursor), add a class that grows the cursor and changes its color. For magnetic CTAs, calculate the cursor's offset from the button's center and apply a translate to the button itself (10–20% of the offset).

cursor: noneHide the OS cursor inside the container so only the custom one shows
requestAnimationFrame + lerpCursor lerps toward target each frame — smooth physics-feel
mix-blend-mode: differenceCursor inverts colors below it — works on light AND dark sections
Magnetic offsetButton translates 10–20% of the cursor's offset from its center
Tip. Always disable custom cursors below 768px (touch devices have no cursor). And keep the native cursor for form inputs — typing without a caret-cursor is jarring.

Live demo

Move your mouse inside the demo. Hover the cards and the big CTA — feel the magnet pull.

Live · mouse only
↕ move cursor inside
View →

Hover anything.
Watch the cursor react.

The dot grows on links, snaps onto the big CTA, and inverts colors over light surfaces using mix-blend-mode.

Start the journey

Copy this prompt

Prompt · 2.8 Magnetic Cursor
Build a custom cursor system. Apply cursor:none to the page container and all its descendants. Create a position:absolute cursor div (16px circle, brand accent color, transform-origin center). On mousemove, set CSS variables --x and --y on the container and lerp the cursor's transform toward them via requestAnimationFrame (with a 0.15 lerp factor for smooth easing). Add mix-blend-mode:difference so the cursor inverts over light and dark backgrounds equally well. For interactive elements (links, buttons), add data-cursor attribute — on mouseenter, add a .hovering class to the cursor that grows it to 60px and changes the background to white. For magnetic CTAs (data-cursor="cta" data-magnet), additionally apply a translate to the button equal to 18% of the cursor's offset from the button's center on mousemove, returning to 0,0 on mouseleave. Show a small text label inside the cursor when over a CTA ("View →"). Disable the entire system on touch devices (window.matchMedia('(hover: none)').matches) and inside form inputs.

Example sites to study