Skip to content

Magnetic

Pull an element toward a nearby pointer and return it when the pointer leaves.

import { Magnetic, MagneticInner } from '@youj/motion'

Installation & usage

npm i @youj/motion

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use it on one or two calls to action that should feel alive: a hero's primary button, a floating action. It rewards the pointer on its way to the target. Keep it out of dense interfaces like toolbars, forms, menus and tables, where targets must stay exactly where they are, and don't put it on text.

Wrap the control. Magnetic is an inline-block wrapper that moves by transform, so the control keeps its layout, its semantics and its focus ring.

import { Magnetic, MagneticInner } from '@youj/motion'
import { Button } from '@youj/react'

export function Cta() {
  return (
    <Magnetic strength={0.3} radius={48}>
      <Button size="lg">
        <MagneticInner>Start deploying</MagneticInner>
      </Button>
    </Magnetic>
  )
}

Reference

Propsstrength, radius, spring… (6)

Props

Magnetic props
PropType
strengthnumber

Fraction of the pointer offset the element follows.

default 0.35

0.35
radiusnumber

Pull starts this many px outside the element's box and grows toward it.

default 80

80
springSpringToken
'snappy''smooth''settle'

default 'smooth'

'smooth'
childrenReactNode–
Other props pass through: extends HTMLMotionProps<'div'>.

MagneticInner

MagneticInner props
PropType
rationumber

How far the inner content travels relative to the shell. 0.5 = half as far.

default 0.5

0.5
childrenReactNode–
Other props pass through: extends HTMLMotionProps<'span'>.
MotionPull, return, magneticInner · reduced motion

Motion

Motion tokens
MomentTokens
Pullstrength × the pointer offset, fading to zero at radius
spring.smooth

0.36s, bounce 0

0.36s, bounce 0
Returnthe pointer leaves the zone or the page, or the window loses focus
spring.smooth

0.36s, bounce 0

0.36s, bounce 0
MagneticInnerrides the same spring at ratio of the travel
spring.smooth

0.36s, bounce 0

0.36s, bounce 0

Reduced motion

No pull. The element stays in place and works as usual.

spring swaps the default for another spring token. snappy tracks the pointer more tightly, and settle adds a small overshoot on the way home. Only transform moves, so the pull never triggers layout.

Reduced motion

Magnetic doesn't listen to the pointer at all, and the control sits exactly where the layout put it. Nothing else changes: the button is fully usable, and MagneticInner renders its content in place.

AccessibilityKeyboard, ARIA, focus

Accessibility

  • Magnetic adds no roles and doesn't take focus. The control inside keeps its own name, keyboard behavior and focus ring.
  • The pull moves the element toward the pointer, so the target gets closer, never harder to hit.
  • It's off when the primary pointer is coarse, as on phones and tablets. Keyboard focus never pulls, so for keyboard users the control stays put.
  • Keep the pull small. A button that travels far from its label, or away from the pointer, feels unstable, and moving targets are hard to use for people with motor impairments.