July 6, 2025

How to Add Page Transitions in Next.js with Motion (Framer Motion Guide)

Md. Saad

Page-Transitions-in-Next.js-with-Motion

Introduction

Enhancing a Next.js application with fluid animations is more than just adding "eye candy"; it also increases user engagement and perceived performance. In this tutorial, we learn how to build a high-performance, animated single-page application using the Motion library, which is the next development of Framer Motion.

Why Choose Motion for Next.js?

Motion is Framer Motion's contemporary replacement. Declarative in nature, you specify the desired state of an element while the library manages the intricate calculations for GPU acceleration and CSS transitions.

  • Server Component Compatibility: To keep your SEO-rich content on the server while it animates on the client, use motion/react-client.
  • Performance: To avoid layout thrashing, hardware-accelerated transforms (such as scale and rotate) are used.

Getting Started: Installation

Start by creating a new Next.js project:

npx create-next-app@latest next-motion

Then, install the Motion library:

yarn add motion
# or
npm install motion

Now open your project in VS Code and install the motion package.

Understanding Framer Motion Core Properties

You need to comprehend the "lifecycle" of an animation property to master Motion:

initial (Starting State)

Purpose: Defines the CSS values of a component before it mounts.

Technical Logic: Sets the baseline styles immediately upon render, often used to hide elements (e.g., opacity: 0) so they can be transitioned in.

animate (Final State)

Purpose: The properties the element "moves toward" automatically.

Technical Logic: Framer Motion detects the difference between initial and animate and applies the necessary interpolation to reach this state.

whileInView (Viewport Trigger)

Purpose: Triggers animations specifically when the element enters the user's visible screen area.

Technical Logic: Leverages the Intersection Observer API to detect scroll position relative to the element's bounding box.

transition (Animation Math)

Purpose: Controls the "feel" of the movement (velocity, easing, and delay).

Technical Logic: Configures the underlying physics (like spring or tween) and timing functions used to calculate the frames between states.

Creating a Rotating Item (Animation Loops)

A continuous animation loop is demonstrated by this component.

'use client';
import { motion } from 'motion/react';
export default function Rotate() {
  return (
    <motion.div
      animate={{ rotate: 360 }}
      transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
      className="w-48 h-48 bg-blue-500 rounded-2xl flex items-center justify-center text-white"
    >
      <span className="font-bold">Next.js + Motion</span>
    </motion.div>
  );
}

Code Elaboration:

  • animate={{ rotate: 360 }}: Tells the browser to change the CSS transform property from 0 to 360 degrees.
  • repeat: Infinity: Creates a perpetual loop, ideal for loading states or background icons.
  • ease: "linear": This is crucial for rotations. Unlike the default "ease-out" which slows down at the end, linear ensures the speed stays constant, preventing a "hitch" in the animation loop.

The Drop-In Navbar (Spring Physics)

Linear animations seem robotic. Your user interface will feel like a tangible object with weight and momentum when you use Spring Physics.

'use client'
import { motion } from 'motion/react'
 
export default function Navbar() {
  return (
    <motion.nav
      initial={{ y: -100, opacity: 0 }}
      animate={{ y: 0, opacity: 1 }}
      transition={{ type: 'spring', stiffness: 120, damping: 20 }}
      className="fixed top-0 w-full p-4 bg-white/80 backdrop-blur-md shadow-sm z-50"
    >
      <div className="flex justify-center gap-8">
        <a href="#about">About</a>
        <a href="#contact">Contact</a>
      </div>
    </motion.nav>
  )
}

Code Elaboration:

  • initial={{ y: -100 }}: Moves the element 100px off the top of the screen before the user sees it.
  • type: 'spring': Swaps the duration-based timer for a physics-based engine.
  • stiffness: 120: Controls how much "tension" is in the spring. High stiffness = faster snap.
  • damping: 20: This acts like friction. It prevents the navbar from bouncing forever. A value of 20 ensures a smooth, single "settle" into place.

Advanced Staggered Scroll Effects

Instead of animating a whole grid at once, we "stagger" them. This guides the user's eye across the content.

const services = ['UI Design', 'DevOps', 'SEO'];
export default function ScalingCards() {
  return (
    <div className="grid grid-cols-3 gap-6">
      {services.map((service, index) => (
        <motion.div
          key={service}
          initial={{ scale: 0.8, opacity: 0 }}
          whileInView={{ scale: 1, opacity: 1 }}
          transition={{ delay: index * 0.2, duration: 0.5 }}
          viewport={{ once: true, margin: "-10% 0px" }}
          className="p-8 bg-gray-50 rounded-xl"
        >
          {service}
        </motion.div>
      ))}
    </div>
  )
}

Code Elaboration:

  • whileInView: Automatically detects when the user has scrolled to this section.
  • delay: index * 0.2: This is the magic line. By multiplying the array index by 0.2, the first card delays 0s, the second 0.2s, and the third 0.4s. This creates a "wave" effect
  • .viewport={{ once: true }}: This prevents the animation from resetting every time the user scrolls up and down, which improves performance and avoids "animation fatigue" for the user.

Motion in Server Components (SEO Optimization)

Traditionally, Framer Motion required the 'use client' directive, which stripped away some SEO benefits. By using motion/react-client, we can get the best of both worlds.

import * as motion from "motion/react-client";
 
export default function HomePage() {
  return (
    <main>
      <motion.h1 
        initial={{ opacity: 0 }} 
        animate={{ opacity: 1 }}
        className="text-6xl font-black"
      >
        Performance Matters.
      </motion.h1>
    </main>
  );
}

Code Elaboration:

  • motion/react-client: This enables the Server Component to display the static HTML (which can be readily read by Google bots) while at the same time sending instructions to the client to apply the animation as soon as the page is interactive.
  • SEO Benefit: Your keywords such as "Performance Matters" are present in the initial HTML source, not just generated by JavaScript after the page loads.

Final Thoughts

No longer is it a choice of beauty versus speed when building an animated Next.js site. With Motion's hardware-accelerated transitions and Next.js Server Components, you can now make a site that ranks well and is a treat to look at.

Need help with Next.js animation or Motion integration? Let's consult with the expert developer to scale the Next.js app.

FAQs

To add animations, install the Motion library and wrap your components using motion elements like motion.div. You can define how elements enter or behave using simple properties like initial, animate, and transition.

Yes, you can. Motion works natively in client components. For server components, a special import allows safe rendering without hydration issues, letting you keep animation logic where you need it.

Use a combination of scroll detection and motion animations to reveal sections when they enter the viewport. This is perfect for building interactive, scroll-friendly landing pages and keeps users engaged.

Staggered animations are great for things like feature cards or service lists. You can apply delays to each item so they animate one after the other, giving your content a more dynamic and polished feel.

Yes. One of Motion's strengths is combining effects easily. You can animate multiple properties in sync—like scaling up while fading in and rotating into view—to create eye-catching transitions.

In many cases, yes. Motion offers more flexibility, better integration with React's lifecycle, and smoother handling of complex UI interactions, like scroll, route transitions, and dynamic layouts.

Share this post