proNew208 lines · framer-motion
Cursor Magnetic Buttons
Buttons that lean in before you even click. A bounded demo panel of sample buttons that spring toward the pointer once it's within range, with the label pulling slightly harder than the button shell for a two-layer magnetic feel, then snap back to rest when the pointer moves away.
- Use it for
- A nav, toolbar or CTA row on a product or portfolio site that wants its buttons to feel physically responsive instead of just having a hover colour change.
- Themes
- Light + dark
- License
- Commercial use
Live
Pointer field
Buttons with a pull
Move your pointer near a button; it leans toward you, then springs back.
tsx
"use client";
import * as React from "react";
import { motion, useReducedMotion, useSpring } from "framer-motion";
import { cn } from "@/lib/utils";
function useReducedMotionSafe() {
const prefersReduced = useReducedMotion();
const [mounted, setMounted] = React.useState(false);
React.useEffect(() => setMounted(true), []);
return mounted ? !!prefersReduced : false;
}
/**
* A bounded demo panel holding 3–4 sample buttons. While the pointer is
* inside the panel and within `radius` of a button, that button (and its
* label, at a slightly stronger pull for a two-layer feel) springs toward
* the pointer, falling off with distance and clamped to a max offset; it
* snaps back on a spring once the pointer leaves its field or the panel.
* Tracking is scoped to the panel element (never `window`) and the whole
* effect falls back to perfectly static, clickable buttons on touch devices
* and under `prefers-reduced-motion`.The rest is in Pro.
Full source, the rebuild prompt and registry install unlock with Pro or Lifetime.
Get ProHow it behaves
- →On every pointer move inside the panel, each button's centre distance to the pointer is measured; inside radius it's pulled toward the pointer with strength falling off quadratically with distance, clamped to a max offset.
- →The button shell and its inner label+icon move on independent springs at different strengths, so the label visibly leads the shell for a layered magnetic feel.
- →Buttons spring back to their resting position on their own once the pointer leaves their field, and all of them reset together when the pointer leaves the panel.
- →strength scales the pull and both max offsets; radius sets how far the field reaches; buttonCount renders 3 or 4 of the sample buttons; shape switches between pill (label + icon) and circle (icon only).
- →Pointer tracking is bound to the panel element via onPointerMove/onPointerLeave — never window — so nothing moves outside the bounded box.
- →On touch devices (pointer: coarse or hover: none) and under prefers-reduced-motion, the pointer handler is a no-op: buttons sit still and are perfectly clickable, with the normal cursor.
Accessibility
- ✓Every button is a real `<button>` the whole time; the magnetic pull is only a `transform` via framer-motion `style`, so click handling, keyboard focus and activation (Enter/Space) all keep working unchanged.
- ✓`:focus-visible` outlines render on the button itself, so they stay anchored to it even while it's magnetically offset.
- ✓Icons are `aria-hidden`; each button's visible label is its only accessible name.
- ✓Honours prefers-reduced-motion.