CSS spring example: Step-by-step

Matt PerryMatt Perry

In this tutorial, we'll build the CSS spring example step-by-step.

This example is rated 1/5 difficulty, which means we'll spend some time explaining the Motion APIs that we've chosen to use (and why), and also any browser JavaScript APIs we encounter that might be unfamiliar to beginners.

Introduction

The CSS Spring example shows how to create natural-feeling CSS transitions using spring physics in React.

In this tutorial, we'll learn to use the spring function from Motion to achieve this.

Get started

Let's start with the basic structure and functionality of our component:

"use client"
 
import { useState } from "react"
 
export default function CSSGeneration() {
    const [state, setState] = useState(false)
 
    return (
        <div className="example-container">
            <div className="box" data-state={state} />
            <button onClick={() => setState(!state)}>Toggle position</button>
 
            <style>
                {`
                    .example-container {
                        display: flex;
                        flex-direction: column;
                        align-items: center;
                        justify-content: center;
                        gap: 20px;
                    }
 
                    .example-container .box {
                        width: 100px;
                        height: 100px;
                        background-color: #0055ff;
                        border-radius: 10px;
                        transition: transform 0.3s ease;
                        transform: translateX(-100%);
                    }
 
                    .example-container .box[data-state="true"] {
                        transform: translateX(100%) rotate(180deg);
                    }
 
                    .example-container button {
                        background-color: #0055ff;
                        color: #000000;
                        border-radius: 5px;
                        padding: 10px;
                        margin: 10px;
                    }
                `}
            </style>
        </div>
    )
}

We're using React's useState to create a state that moves the box between two positions. This state is toggled when the button is clicked.

If you try this code, you'll see that the box moves smoothly between the two positions. However, the animation uses a basic easing curve, which doesn't feel as natural as a spring-based animation would.

Let's animate!

Now we'll transform this basic animation into a spring animation.

Import from Motion

First, let's import the spring function from Motion:

import { spring } from "motion"

Animations

Now let's replace the standard CSS transition with a spring animation:

.example-container .box {
    width: 100px;
    height: 100px;
    background-color: #0055ff;
    border-radius: 10px;
    transition: transform ${spring(0.5, 0.8)};
    transform: translateX(-100%);
}

We've replaced transition: transform 0.3s ease with transition: transform ${spring(0.5, 0.8)}.

spring accepts two parameters:

spring can be used to sample points on a string, but by passing it into a string it returns a calculated duration and CSS linear() easing function.

The reason why duration is considered a perceived duration is because this is roughly the amount of time it takes for the animation to complete, disregarding the bounciness of the spring.

This makes it easier to reason about the animation and synchronize it with other animations. If you want to make the spring bouncier, you can simply change the second parameter, while leaving the duration the same.

Conclusion

In this tutorial, we've learned how to:

Spring animations are perfect for creating more natural, engaging UIs. They're especially useful for transitional actions, like the one in this example, where elements need to physically move between defined states in a way that feels responsive.

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.