NCSS/Motion Engine™

Magnetic Button

A premium, high-performance UI component built with Tailwind CSS and React.

Preview

Installation

Add the required dependencies if you haven't already:

1npm install framer-motion clsx tailwind-merge

Copy and paste the following code into your project:

1"use client";
2
3import { motion, useMotionValue, useSpring, useTransform } from "framer-motion";
4import { useRef, useState } from "react";
5import { cn } from "@/lib/utils";
6
7export default function MagneticButton({
8 children = "Hover Me",
9 className
10}) {
11 const ref = useRef(null);
12 const [isHovered, setIsHovered] = useState(false);
13
14 const x = useMotionValue(0);
15 const y = useMotionValue(0);
16
17 // Smooth spring physics for the magnetic effect
18 const springConfig = { damping: 15, stiffness: 150, mass: 0.1 };
19 const springX = useSpring(x, springConfig);
20 const springY = useSpring(y, springConfig);
21
22 const handleMouseMove = (e) => {
23 if (!ref.current) return;
24 const rect = ref.current.getBoundingClientRect();
25 const centerX = rect.left + rect.width / 2;
26 const centerY = rect.top + rect.height / 2;
27
28 // Magnetic pull strength (higher is stronger)
29 const pull = 0.3;
30 x.set((e.clientX - centerX) * pull);
31 y.set((e.clientY - centerY) * pull);
32 };
33
34 const handleMouseLeave = () => {
35 setIsHovered(false);
36 x.set(0);
37 y.set(0);
38 };
39
40 return (
41 <div
42 className="p-8 inline-block" // Safe area to catch hover before hitting button bounds
43 onMouseMove={handleMouseMove}
44 onMouseEnter={() => setIsHovered(true)}
45 onMouseLeave={handleMouseLeave}
46 >
47 <motion.button
48 ref={ref}
49 style={{
50 x: springX,
51 y: springY,
52 }}
53 className={cn(
54 "relative px-8 py-4 rounded-full font-semibold text-white transition-colors duration-300",
55 "bg-gradient-to-r from-blue-600 to-indigo-600 shadow-[0_0_20px_rgba(79,70,229,0.3)]",
56 isHovered && "from-blue-500 to-indigo-500 shadow-[0_0_30px_rgba(79,70,229,0.5)]",
57 className
58 )}
59 >
60 {children}
61 </motion.button>
62 </div>
63 );
64}
65