Magnetic
FreeWraps one button or link so it leans toward the pointer as it comes near, up to 8px, and settles back when the pointer leaves.
pnpm dlx shadcn@latest add https://caliperui.site/r/magnetic.jsonWhen to use #
Use it for
- The one or two actions you want people to notice, such as a hero button.
- Marketing and onboarding surfaces where a little life helps.
Skip it when
- Dense toolbars and tables; many things leaning at once is noise.
- Touch and keyboard: it does nothing there, so nothing may depend on it.
Decisions #
Why it is built this way, so you know what to keep when you change your copy.
Behaviour
- Only the wrapper moves
- The control inside keeps its own press, focus ring and hit area, so activation never changes. The lean is a follow with a soft settle, not a spring that overshoots.
- Fine pointers only
- Touch, keyboard focus and reduced motion get no lean at all. Nothing important may depend on it.
Usage
- Wrap one child
- A lean larger than 8px starts to feel like the button is running away, so the limit is part of the part.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/magnetic.json
Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
import { Button } from "@/components/ui/button" import { Magnetic } from "@/components/ui/magnetic" export function MagneticDemo() { return ( <div className="flex flex-wrap items-center justify-center gap-8 px-4 py-10"> <Magnetic><Button size="lg">Start free</Button></Magnetic> <Magnetic><Button size="lg" variant="secondary">Read the docs</Button></Magnetic> <Magnetic><Button size="lg" variant="ghost">View on GitHub</Button></Magnetic> </div> ); }
API reference #
Magnetic
component
Also accepts the native props of its root element and a ref.
Accessibility #
It is built on native elements, so roles and focus come from the browser.
No custom key handling; Tab and the native activation keys do the work.
Motion #
It checks prefers-reduced-motion itself and settles immediately instead of travelling. Every state is still reachable.