@vectorvesper/motion/reactReact · Magnetic Physics

useMagneticIntent

Traditional magnetic hover buttons only react once the pointer enters their bounding box, feeling sluggish and delayed. useMagneticIntent fuses pointer trajectory prediction with proximity falloff, beginning attraction physics while the cursor is still travelling towards the target.

The useMagneticIntent hook binds a DOM element to an anticipatory magnetic pull. It computes an engagement value from 0.0 to 1.0 based on the maximum of PointerIntent approach confidence and geometric proximity falloff.

The hook reads element anchor bounds in the conductor input lane before any subscriber writes, and updates DOM transform properties in the render lane. This separation guarantees zero forced synchronous reflows even when dozens of magnetic elements animate concurrently.

Anchor positions are automatically compensated against current translation offsets (anchor = rectCenter - currentOffset), preventing the element from chasing its own displaced centre. When running on touch devices or under reduced motion preferences, the hook gracefully sits idle and leaves the element at rest.

Multi-Element Magnetic Grid

prefers-reduced-motion: offfine pointer: yes
Demo loads on scroll

Quick start

Attach the returned ref to your button. The hook manages spring-damped translation and scale transforms automatically.

The hook takes exclusive ownership of the element inline transform while mounted, restoring original inline styles on unmount.

Input Lane Separation & Anchor Stability

How the magnetic physics pipeline prevents layout thrashing and anchor drift across multi-element pages.

1. Layout Read / Transform Write Pipeline

Calling getBoundingClientRect() inside render callbacks forces synchronous layout recalculation when multiple elements animate. MagneticElement schedules anchor measurements strictly in the input lane, caching rects across frames and re-measuring only during scroll, resize, or periodic heartbeats.

2. Anchor Drift Compensation

As the element translates towards the pointer, its live bounding box moves with it. To prevent runaway drift, the anchor coordinate is calculated by subtracting the current translation offset from the element centre: anchorX = rect.left + width/2 - currentOffsetX.

API Reference

Syntax

Binds an element to predictive magnetic pull with spring-damped tracking.

Parameters

Parameters.fieldTypeDefaultDescription
options.strengthnumber12Maximum offset in pixels at full magnetic engagement.
options.reachnumber90Proximity radius in pixels from resting centre where attraction begins.
options.speednumber12Spring follow and release speed. Higher values create a tighter, snappier chase.
options.scalenumber1.04Scale multiplier applied at full engagement. Set to 1.0 to disable scaling.
options.anticipatebooleantrueEnables trajectory prediction to start reaching before cursor contact. Disable for dense grids.

Return Value

{ ref: RefObject<T | null>; active: boolean }

Ref to attach to target element and boolean active status (true when running on fine pointer).

Properties & State

Properties.fieldTypeDescription
refRefObject<T | null>DOM ref attached to the element whose transform is animated.
activebooleanTrue when running on a fine pointer without reduced-motion constraints.

Inline Transform Restoration & Teardown

MagneticElement preserves original inline styles and restores them cleanly upon unmount.

1. Transform RestorationClean style teardown
2. Vanilla JS ClassManual instance destruction

Lifecycle & Invariant Guarantees

  • Zero forced synchronous reflows: Measurements execute in the input lane before any transform writes occur, preventing multi-element layout thrashing.
  • Style state preservation: Previous inline transform strings are recorded and restored exactly when the component unmounts.
  • Accessibility and touch safety: Bails out automatically on touch-only devices and when prefers-reduced-motion is active.
  • Frame-rate independent damping: Spring physics use delta-time damping, behaving consistently across 60Hz, 120Hz, and 240Hz screens.

Production Examples

Battle-tested production patterns ready to copy directly into your codebase.

Single hero action button with anticipatory pull enabled for high-fidelity desktop experience.

When NOT to use this

Standard text inputs, dense menus, or essential navigation links.
→ instead Keep elements static. Moving targets make clicking harder, particularly for users with motor impairments.
Applying custom continuous transforms to the same DOM node.
→ instead Place the magnet on a parent wrapper and custom transforms on a child element to avoid transform overwrite conflicts.
Targeting touch mobile devices.
→ instead The hook automatically disables itself on coarse pointers. Design static hover states for mobile.

Rules & Gotchas

  • Enable anticipate for single CTAs, disable for dense grids: Anticipation executes trajectory prediction per element. Keep enabled for hero buttons and disabled for tile grids.
  • Keep strength modest on interactive controls: Excessive travel distance makes buttons harder to click. Keep strength between 8px and 16px for interactive elements.
  • Separate compound transforms onto child nodes: The hook takes exclusive ownership of the ref node inline transform. Place static rotations on child elements.
  • Preserve accessible focus styling: Magnetic attraction is a visual enhancement; keyboard focus outlines and accessibility labels must remain fully functional.

Related Motion Components