In this post, I’ll show you how to implement an interactive magnetic effect in Next.js using React and GSAP. This component is perfect for creating dynamic and engaging interactions for users, ideal for buttons, links, or any element you want to highlight.
The React Component with Magnetic Logic
The Magnetic
component is the core of this functionality. With GSAP and a bit of JavaScript magic, it tracks cursor movement to apply the magnetic effect. Additionally, the component is flexible enough to be used with icons and buttons.
Code: src/components/MagneticElement/index.jsx
"use client";
import React, { useEffect, useRef, useState } from "react";
import { gsap } from "gsap";
import { useGSAP } from "@gsap/react";
import "./styles.css";
const Magnetic = ({ children, className, onClick, power = 50, iconVariable }) => {
const magnetRef = useRef(null);
const [strength, setStrength] = useState(power);
useEffect(() => {
const mm = gsap.matchMedia();
mm.add("(max-width: 540px)", () => {
setStrength(0);
});
}, []);
useGSAP(() => {
const magnetButton = magnetRef.current;
const moveMagnet = (event) => {
const bounding = magnetButton.getBoundingClientRect();
gsap.to(magnetButton, 2, {
x: ((event.clientX - bounding.left) / magnetButton.offsetWidth - 0.5) * strength,
y: ((event.clientY - bounding.top) / magnetButton.offsetHeight - 0.5) * strength,
ease: "elastic"
});
};
const resetMagnet = (event) => {
gsap.to(event.currentTarget, 2, {
x: 0,
y: 0,
ease: "elastic"
});
};
magnetButton.addEventListener("mousemove", moveMagnet);
magnetButton.addEventListener("mouseout", resetMagnet);
return () => {
magnetButton.removeEventListener("mousemove", moveMagnet);
magnetButton.removeEventListener("mouseout", resetMagnet);
};
}, [strength]);
return (
<div
className={`magneticBox ${className || ''} ${iconVariable ? "iconBox" : ""}`}
ref={magnetRef}
onClick={onClick}
>
{children}
{iconVariable && (
<span className="iconButton">
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" fill="none" viewBox="0 0 10 10">
<path
fill="#F8F8F8"
fillRule="evenodd"
d="M.726 9.7a.446.446 0 00.318.131c.12 0 .235-.049.32-.134l7.56-7.56-.022 4.014a.447.447 0 00.77.316.456.456 0 00.133-.32l.026-5.102a.448.448 0 00-.276-.416.448.448 0 00-.173-.034L4.28.621a.454.454 0 00-.454.454.447.447 0 00.45.45l4.013-.022-7.56 7.56a.456.456 0 00-.134.32c0 .119.047.233.13.318z"
clipRule="evenodd"
/>
</svg>
</span>
)}
</div>
);
};
export default Magnetic;
Associated CSS Styles
These styles help shape the component and the optional icon.
Code: src/components/MagneticElement/styles.css
.magneticBox {
width: fit-content;
display: flex;
justify-content: center;
align-items: center;
}
.magneticBox .iconButton {
display: flex;
background-color: rgba(0, 0, 0, 0.15);
border-radius: 100px;
border: 1px solid rgba(255, 255, 255, 0.08);
padding: 12px;
width: 40px;
height: 40px;
}
.magneticBox .iconButton svg {
width: 100%;
}
How to Use the Component
To use the component, simply import it and place it where needed:
import Magnetic from './components/MagneticElement';
// Basic Usage
<Magnetic>
<button>Hover me!</button>
</Magnetic>
// With Icon
<Magnetic power={30} iconVariable={true}>
Link with icon
</Magnetic>
Installing Dependencies
Don’t forget to install the required dependencies before using the component:
npm install gsap @gsap/react
This component is just the beginning of what you can achieve by combining GSAP and React in Next.js. If you’re interested in adding this kind of functionality to your project or have even crazier ideas, feel free to reach out—I’d love to help you bring them to life! 🚀