AnimBits
componentbuttons-magneticsource: ok · refreshed
Magnetic Button
Button with cursor-following magnetic attraction effect
npx shadcn add "https://animbits.dev/r/buttons-magnetic.json"free
Interaction
cursor-follow
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · mediumanimationmotion
Files2 · source cached 10/8/2026, 6:17:41 AM
registry/new-york/animations/buttons/magnetic.tsx
"use client";
import * as React from "react";
import { motion, HTMLMotionProps } from "motion/react";
import { cn } from "@/lib/utils";
import { useMagnetic, type UseMagneticOptions } from "@/lib/use-magnetic";
interface MagneticButtonProps
extends Omit<HTMLMotionProps<"button">, "ref">,
UseMagneticOptions {
children: React.ReactNode;
}
export function MagneticButton({
children,
className,
strength,
stiffness,
damping,
...props
}: MagneticButtonProps) {
const { magneticProps, ref } = useMagnetic({ strength, stiffness, damping });
return (
<motion.button
ref={ref as any}
{...magneticProps}
className={cn(className)}
{...props}
>
{children}
</motion.button>
);
}
lib/use-magnetic.ts
import * as React from "react";
import { useMotionValue, useSpring } from "motion/react";
export interface UseMagneticOptions {
strength?: number;
stiffness?: number;
damping?: number;
}
export function useMagnetic(options: UseMagneticOptions = {}) {
const { strength = 30, stiffness = 150, damping = 15 } = options;
const ref = React.useRef<HTMLElement>(null);
const x = useMotionValue(0);
const y = useMotionValue(0);
const springConfig = { damping, stiffness };
const springX = useSpring(x, springConfig);
const springY = useSpring(y, springConfig);
const handleMouseMove = (e: React.MouseEvent<HTMLElement>) => {
if (!ref.current) return;
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;
x.set(distanceX * (strength / 100));
y.set(distanceY * (strength / 100));
};
const handleMouseLeave = () => {
x.set(0);
y.set(0);
};
const magneticProps = {
style: { x: springX, y: springY },
onMouseMove: handleMouseMove,
onMouseLeave: handleMouseLeave,
};
return { magneticProps, ref };
}