Follow pointer with spring example: Step-by-step

Matt PerryMatt Perry

In this tutorial, we'll build the Follow pointer with spring example step-by-step.

This example is rated 2/5 difficulty, which means we'll spend some time explaining the Motion APIs we've chosen to use, but it assumes familiarity with JavaScript as a language.

Introduction

The Follow Pointer with Spring example shows how to make an element smoothly follow your cursor with a spring-like motion. This creates a natural, physical feeling as the element trails behind your mouse movements.

This example uses two key Motion APIs:

Spring animations are a great way to add natural motion to your UI because they mimic the behavior of real-world physics. Unlike linear or easing animations, springs respond to changes in velocity, making the motion feel more organic, especially when following user input like mouse movement.

Get started

Let's start by creating a basic component with a ball that will follow our pointer:

"use client"
 
import { motion } from "motion/react"
import { useRef } from "react"
 
export default function Drag() {
    const ref = useRef<HTMLDivElement>(null)
 
    return <motion.div ref={ref} style={ball} />
}
 
const ball = {
    width: 100,
    height: 100,
    backgroundColor: "#5686F5",
    borderRadius: "50%",
}

This gives us a simple blue circle on the screen, but it doesn't follow our pointer yet.

Let's animate!

Import from Motion

First, we need to import the additional Motion APIs we'll be using:

import { frame, motion, useSpring } from "motion/react"

Creating the spring motion values

Now we'll create a custom hook that will handle the pointer-following logic:

function useFollowPointer(ref) {
    const x = useSpring(0)
    const y = useSpring(0)
 
    // We'll add event handling here
 
    return { x, y }
}

The useSpring hook creates a special type of motion value that animates changes using spring physics. By default, whenever we set a new value, the motion value will animate to that target with a natural spring motion rather than jumping instantly.

Customizing the spring

Let's add some spring configuration to control how the following behavior feels:

const spring = { damping: 3, stiffness: 50, restDelta: 0.001 }
 
function useFollowPointer(ref) {
    const x = useSpring(0, spring)
    const y = useSpring(0, spring)
 
    // We'll add event handling here
 
    return { x, y }
}

The spring configuration controls:

Adding pointer tracking

Now we need to track the mouse pointer and update our spring values accordingly:

useEffect(() => {
    if (!ref.current) return
 
    const handlePointerMove = ({ clientX, clientY }) => {
        const element = ref.current
 
        frame.read(() => {
            x.set(clientX - element.offsetLeft - element.offsetWidth / 2)
            y.set(clientY - element.offsetTop - element.offsetHeight / 2)
        })
    }
 
    window.addEventListener("pointermove", handlePointerMove)
 
    return () => window.removeEventListener("pointermove", handlePointerMove)
}, [])

This is fairly standard but pay attention to frame.read. We use this to place the callback on the "read" part of Motion's render loop. This ensures we only update the motion values once per frame, reducing unnecessary work.

Using the motion values

Finally, let's update our component to use our custom hook:

export default function Drag() {
    const ref = useRef<HTMLDivElement>(null)
    const { x, y } = useFollowPointer(ref)
 
    return <motion.div ref={ref} style={{ ...ball, x, y }} />
}

When we pass our motion values directly to the style prop, Motion automatically uses them to drive the transforms of the element. As the values update with spring physics, the element will move accordingly.

Conclusion

In this tutorial, we learned how to create a UI element that follows the pointer with natural spring physics. We used:

This technique can be used for various interactive UI elements like hover effects, custom cursors, or draggable elements with inertia. By adjusting the spring configuration, you can create different feels - from tight, responsive following to loose, bouncy motion.

Tutorial Project

We're currently working on adding a tutorial for every example on the Motion Examples website. So far, 12% of examples have a tutorial.