registry:component

Magnetic Button

v1.0.0ga

Animated button primitive with magnetic cursor pull.

Registry Endpoint
Open JSON

https://registry.aavya.com/r/ui-magnetic-button.json

npx shadcn@latest add https://registry.aavya.com/r/ui-magnetic-button.json

Live Preview
Usage Snippet
import MagneticButton from '@/components/ui/magnetic-button.tsx'

export default function Example() {
  return (
    <div className="p-6">
      <MagneticButton />
    </div>
  )
}
Source Preview
'use client'

import * as React from 'react'

import { motion, type HTMLMotionProps, type Transition } from 'motion/react'
import type { VariantProps } from 'class-variance-authority'

import { cn } from '@/lib/utils'
import { buttonVariants } from '@/components/ui/button'

interface Position {
  x: number
  y: number
}

interface MagneticButtonProps extends HTMLMotionProps<'button'>, VariantProps<typeof buttonVariants> {
  children: React.ReactNode
  scale?: number
  transition?: Transition
}

function MagneticButton({ children, className, size, variant, ...props }: MagneticButtonProps) {
  const ref = React.useRef<HTMLButtonElement>(null)
  const [position, setPosition] = React.useState<Position>({ x: 0, y: 0 })

  const handleMouse = (e: React.MouseEvent<HTMLButtonElement>) => {
    if (ref.current) {
      const { clientX, clientY } = e
      const { height, width, left, top } = ref.current.getBoundingClientRect()
      const middleX = clientX - (left + width / 2)
      const middleY = clientY - (top + height / 2)

      setPosition({ x: middleX, y: middleY })
    }
  }

  const reset = () => {
    setPosition({ x: 0, y: 0 })
  }

  const { x, y } = position

  return (
    <motion.button
      ref={ref}
      onMouseMove={handleMouse}
      onMouseLeave={reset}
      animate={{ x, y }}
      transition={{ type: 'spring', stiffness: 150, damping: 15, mass: 0.1 }}
      whil