Back to Components
Magnetic Button Hover Effect Using HTML, CSS & GSAP | Interactive Cursor Animation
Component

Magnetic Button Hover Effect Using HTML, CSS & GSAP | Interactive Cursor Animation

CodewithLord
October 19, 2025

This project demonstrates a creative magnetic button hover effect built using HTML, CSS, and GSAP (GreenSock Animation Platform).

🧠 Description

This project demonstrates a creative magnetic button hover effect built using HTML, CSS, and GSAP (GreenSock Animation Platform). The design replaces the default cursor with a custom animated cursor that dynamically reacts when hovering over a target button. As the user moves their mouse, the cursor smoothly follows the movement, rotates continuously, and expands or contracts based on hover interactions — creating a magnetic attraction effect. This effect enhances UI interactivity, making it perfect for modern websites, portfolios, and creative interfaces where smooth animations improve user engagement.


💻 HTML Code


1<!DOCTYPE html> 2<html lang="en"> 3 4<head> 5 <meta charset="UTF-8"> 6 <title>Magnetic Button Hover Effect | @coding.stella</title> 7 <link rel="stylesheet" href="./style.css"> 8</head> 9 10<body> 11 <div id="cursor"></div> 12 <div id="cursorPt"></div> 13 <div id="target">Hover me</div> 14 15 <script src="https://unpkg.com/gsap@3/dist/gsap.min.js"></script> 16 <script src="./script.js"></script> 17</body> 18 19</html>

The HTML defines the basic structure of the animation. It includes:

Two divs (#cursor and #cursorPt) that act as the custom cursor elements.

A third div (#target) labeled “Hover me”, which serves as the interactive button. The GSAP library is imported via CDN to handle all motion and animation logic. Finally, an external CSS and JavaScript file are linked to style and animate the elements respectively. In short, the HTML provides the skeleton for the visual and interactive components.


CSS Code


1body { 2 margin: 0; 3 height: 100vh; 4 overflow: hidden; 5 background: linear-gradient(#111, #000); 6 display: flex; 7 cursor: none; 8} 9 10#cursorPt { 11 position: fixed; 12 width: 7px; 13 height: 7px; 14 pointer-events: none; 15 z-index: 9999; 16 background: #beffcb; 17 border-radius: 50%; 18 visibility: hidden; 19} 20 21#cursor { 22 --color: #68fd85; 23 position: fixed; 24 width: 30px; 25 height: 30px; 26 pointer-events: none; 27 z-index: 9999; 28 visibility: hidden; 29 30 background-image: linear-gradient(to right, var(--color) 10px, transparent 0), 31 linear-gradient(to bottom, var(--color) 10px, transparent 0), 32 linear-gradient(to left, var(--color) 10px, transparent 0), 33 linear-gradient(to bottom, var(--color) 10px, transparent 0), 34 linear-gradient(to right, var(--color) 10px, transparent 0), 35 linear-gradient(to top, var(--color) 10px, transparent 0), 36 linear-gradient(to left, var(--color) 10px, transparent 0), 37 linear-gradient(to top, var(--color) 10px, transparent 0); 38 39 background-repeat: no-repeat; 40 background-position: top left, top left, top right, top right, bottom left, 41 bottom left, bottom right, bottom right; 42 background-size: 20px 2px, 2px 20px, 20px 2px, 2px 20px, 20px 2px, 2px 20px, 43 20px 2px, 2px 20px; 44} 45 46#target { 47 position: relative; 48 width: 150px; 49 height: 80px; 50 margin: auto; 51 border: 2px solid #888; 52 transition: 300ms; 53 display: flex; 54 justify-content: center; 55 align-items: center; 56 color: #888; 57 text-transform: uppercase; 58 font-family: sans-serif; 59 user-select: none; 60} 61 62#target:hover { 63 border-color: #ccc; 64 color: #ddd; 65}

The CSS styles the page and defines the cursor visuals and hover behavior.

The body is styled with a dark gradient background, full-screen layout (height: 100vh), and cursor: none to hide the default cursor.

#cursorPt creates a small circular dot that precisely follows the mouse pointer.

#cursor forms the animated magnetic frame, styled with multiple linear gradients to give a neon-border-like look.

Both cursors are set to position: fixed and pointer-events: none to ensure smooth movement without blocking interactions.

The #target button is centered using Flexbox, styled with a gray border, and changes color on hover for visual feedback. Overall, the CSS defines the sleek, futuristic look and positioning of all visual elements.


Javascipt Code


1const cursor = document.getElementById("cursor"); 2const cursorPt = document.getElementById("cursorPt"); 3const target = document.getElementById("target"); 4 5const CURSOR_WIDTH = cursor.getBoundingClientRect().width; 6const CURSOR_PT_WIDTH = cursorPt.getBoundingClientRect().width; 7 8let isOverTarget = false; 9let rotationTween; 10let exitTween = null; 11let enterTween = null; 12 13function startRotation() { 14 gsap.set(cursor, { rotation: 0 }); 15 rotationTween = gsap.to(cursor, { 16 rotation: 180, 17 duration: 1.2, 18 repeat: -1, 19 ease: "linear", 20 transformOrigin: "center center" 21 }); 22} 23 24function stopRotation() { 25 if (rotationTween) rotationTween.kill(); 26} 27 28document.addEventListener("mousemove", (e) => { 29 gsap.to(cursor, {autoAlpha: 1}); 30 gsap.to(cursorPt, {autoAlpha: 1}); 31 if (!isOverTarget) { 32 gsap.to(cursor, { 33 x: e.clientX - CURSOR_WIDTH / 2, 34 y: e.clientY - CURSOR_WIDTH / 2, 35 duration: 0.1, 36 ease: "expo.out" 37 }); 38 } 39 gsap.to(cursorPt, { 40 x: e.clientX - CURSOR_PT_WIDTH/2, 41 y: e.clientY- CURSOR_PT_WIDTH/2, 42 duration: 0.1, 43 ease: "expo.out" 44 }); 45}); 46 47target.addEventListener("mouseenter", () => { 48 isOverTarget = true; 49 stopRotation(); 50 51 const rect = target.getBoundingClientRect(); 52 53 if (exitTween) exitTween.kill(); 54 enterTween = gsap.to(cursor, { 55 width: rect.width, 56 height: rect.height, 57 borderColor: "red", 58 rotation: 360, 59 duration: 0.2, 60 ease: "easeOut" 61 }); 62}); 63 64target.addEventListener("mousemove", (e) => { 65 const rect = target.getBoundingClientRect(); 66 67 const targetWidth = rect.width; 68 const targetHeight = rect.height; 69 70 const cx = rect.left + targetWidth / 2; 71 const cy = rect.top + targetHeight / 2; 72 73 const dx = e.clientX - cx; 74 const dy = e.clientY - cy; 75 76 gsap.to(cursor, { 77 x: rect.left + dx * 0.09, 78 y: rect.top + dy * 0.09, 79 scale: 1.1, 80 duration: 0.1, 81 ease: "power2.out" 82 }); 83}); 84 85target.addEventListener("mouseleave", () => { 86 isOverTarget = false; 87 88 exitTween = gsap.to(cursor, { 89 width: 30, 90 height: 30, 91 duration: 0.5, 92 ease: "elastic.out(1, .9)" 93 }); 94 95 startRotation(); 96}); 97 98startRotation();

The JavaScript file (using GSAP) controls the animations and cursor interactions. Here’s how it works:

It captures references to #cursor, #cursorPt, and #target.

A continuous rotation animation is started using gsap.to() to rotate the cursor frame infinitely.

On mousemove, both cursor elements (cursor and cursorPt) follow the mouse coordinates smoothly using GSAP transitions, making movement feel natural.

When the mouse enters the target button, the cursor expands to match the button’s size, rotation stops, and a subtle animation enlarges the frame — simulating a magnetic pull.

During movement inside the target, the cursor slightly follows the mouse direction inside the button using offset calculations.

When the mouse leaves the target, the cursor returns to its original size with an elastic animation and resumes rotation. These combined animations create a highly interactive and magnetic cursor effect, powered entirely by GSAP’s smooth motion engine.

Love this component?

Explore more components and build amazing UIs.

View All Components