Magnetic Hover Effect

PreviousNext

A Magnetic Button is a UI component designed to enhance user interaction. When a user's cursor or touch input approaches the button, it subtly moves towards the user, simulating the effect of magnetic attraction.

Docs
bunduicomponent

Preview

Loading preview…
examples/motion/animations/magnetic-hover-effect/01/magnetic-effect.tsx
"use client";

import React, { useState, useEffect, useRef } from "react";
import { motion, useMotionValue, useSpring } from "motion/react";

const SPRING_CONFIG = { damping: 100, stiffness: 400 };

type MagneticEffectType = {
  children: React.ReactNode;
  distance?: number;
};

function MagneticEffect({ children, distance = 0.6 }: MagneticEffectType) {
  const [isHovered, setIsHovered] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  const x = useMotionValue(0);
  const y = useMotionValue(0);

  const springX = useSpring(x, SPRING_CONFIG);
  const springY = useSpring(y, SPRING_CONFIG);

  useEffect(() => {
    const calculateDistance = (e: MouseEvent) => {
      if (ref.current) {
        const rect = ref.current.getBoundingClientRect();
        const centerX = rect.left + rect.width / 2;
        const centerY = rect.top + rect.height / 2;
        const distanceX = e.clientX - centerX;
        const distanceY = e.clientY - centerY;

        if (isHovered) {
          x.set(distanceX * distance);
          y.set(distanceY * distance);
        } else {
          x.set(0);
          y.set(0);
        }
      }
    };

    document.addEventListener("mousemove", calculateDistance);

    return () => {
      document.removeEventListener("mousemove", calculateDistance);
    };
  }, [ref, isHovered]);

  return (
    <motion.div
      ref={ref}
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
      style={{
        x: springX,
        y: springY
      }}>
      {children}
    </motion.div>
  );
}

export default MagneticEffect;

Installation

npx shadcn@latest add @bundui/magnetic-hover-effect-01

Usage

import { MagneticHoverEffect01 } from "@/components/magnetic-hover-effect-01"
<MagneticHoverEffect01 />