Components

Magnetic Button

A pill button pulled toward the cursor, its label drifting further for depth.

A pill button with a magnetic field around it. Once the cursor comes within reach, the button leans toward it and grows a touch, while the label drifts a little further for a sense of depth. Leave the field and it eases back to rest. It is a real <button>, so onClick, type, disabled, and refs all work. Driven by GSAP.

New tab

Installation

pnpm dlx shadcn@latest add @tween-ui/magnetic-button

Using an AI editor? Set up MCP once, then just ask for it in plain words.

Usage

app/page.tsx
app/page.tsx
import MagneticButton from '@/components/tweenui/magnetic-button';
 
export default function Page() {
  return (
    <MagneticButton strength={0.4} field={80} onClick={() => console.log('clicked')}>
      Get started
    </MagneticButton>
  );
}

While the cursor is in the field the button carries a data-active attribute, so restyle that state with Tailwind — for example className="bg-black text-white data-[active]:bg-white data-[active]:text-black".

Props

Extends every native <button> attribute (onClick, type, disabled, ref, …).

PropTypeDefaultDescription
childrenReactNode—Button label.
strengthnumber0.35How strongly the button follows the cursor, from 0 to 1.
fieldnumber60Distance around the button, in pixels, where the pull begins.
parallaxnumber0.35Extra drift of the label on top of the button's own.
hoverScalenumber1.05Scale while the cursor is inside the field.
durationnumber0.6How long the button takes to catch up with the cursor, in seconds.
type'button' | 'submit' | 'reset''button'Native button type.
classNamestring—Merged with the base styles.

Accessibility

It renders a native <button>, so keyboard and screen-reader behaviour come for free, and keyboard focus shows the active colors with a visible ring. The pull is skipped entirely on touch devices, for disabled buttons, and under prefers-reduced-motion: reduce.