chetoui hamza
🙂
chetoui hamza

Remix guid to animated routes with framer motion.

Animating Remix Pages with Motion

Remix (React router v7) is a powerful web framework that allows for fast, dynamic routing. When combined with Motion, you can create smooth, animated transitions between pages (Routes), enhancing the user experience. This article will guide you through the process of adding page transition animations to your Remix application using Motion.

Prerequisites

Before we begin, make sure you have:

  1. A basic understanding of React and Remix

  2. Remix installed in your project

  3. Framer Motion installed (npm install framer-motion or yarn add framer-motion)

Setting Up Your Remix Project

Let’s start with a typical Remix project structure:

app/
├── routes/
│   ├── _index.tsx
│   └── about.tsx
└── root.tsx

Your root.tsx file might look something like this:

import {
  Links,
  Meta,
  Outlet,
  Scripts,
  ScrollRestoration,
} from "@remix-run/react";

export default function Root() {
  return (
    <html lang="en">
      <head>
        <Links />
        <Meta />
      </head>
      <body>
        <Outlet />
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

Step 1: Create Motion Components

First, we’ll wrap our page content in Framer Motion components. Update your route files (_index.tsx and about.tsx) like this:

import { motion } from 'framer-motion';

const MotionPage = motion.div;

export default function Index() {
  return (
    <MotionPage>
      <h1>/</h1>
      <p>index page</p>
    </MotionPage>
  );
}

Do the same for the about.tsx file.

Step 2: Set Up AnimatePresence

To enable enter/exit animations, we need to use Framer Motion’s AnimatePresence component. Update your root.tsx:

import {
  Links,
  Meta,
  useOutlet,
  useLocation,
  Scripts,
  ScrollRestoration,
} from "@remix-run/react";
import { AnimatePresence } from "framer-motion";

export default function Root() {
  const outlet = useOutlet();
  const location = useLocation();

  return (
    <html lang="en">
      <head>
        <Links />
        <Meta />
      </head>
      <body>
        <AnimatePresence mode='wait' initial={false}>
          <div key={location.pathname}>
            {outlet}
          </div>
        </AnimatePresence>
        <ScrollRestoration />
        <Scripts />
      </body>
    </html>
  );
}

Note: We use useOutlet() instead of <Outlet /> to allow for exit animations.

i tried both and <Outlet/> skip exit animation

Step 3: Define Animation Variants

Create a new file variants.ts to define your animation variants:

export const pageVariants = {
  initial: {
    opacity: 0,    y: 50,  },  in: {
    opacity: 1,    y: 0,    transition: {
      duration: 0.3,      ease: "easeOut",    },  },  out: {
    opacity: 0,    y: -50,    transition: {
      duration: 0.3,      ease: "easeIn",    },  },};

Step 4: Apply Animations to Pages

Now, update your route components to use these variants:

import { motion } from 'framer-motion';
import { pageVariants } from '../variants';

export default function Index() {
  return (
    <motion.div
      initial="initial"
      animate="in"
      exit="out"
      variants={pageVariants}
    >
      <h1>/</h1>
      <p>index page</p>
    </motion.div>
  );
}

Apply the same changes to about.tsx.

Step 5: Staggering Children Animations (Optional)

For more complex pages, you might want to stagger the animation of child elements. Here’s how you can do that:

// In variants.ts export const containerVariants = {
  hidden: {
    opacity: 0,    y: 50,    transition: {
      when: "afterChildren",      staggerChildren: 0.1,    },  },  visible: {
    opacity: 1,    y: 0,    transition: {
      when: "beforeChildren",      staggerChildren: 0.1,    },  },};export const itemVariants = {
  hidden: { opacity: 0, y: 20 },  visible: { opacity: 1, y: 0 },};

Then in your route component:

import { motion } from 'framer-motion';
import { containerVariants, itemVariants } from '../variants';

export default function About() {
  return (
    <motion.div
      initial="hidden"
      animate="visible"
      exit="hidden"
      variants={containerVariants}
    >
      <motion.h1 variants={itemVariants}>/about</motion.h1>
      <motion.p variants={itemVariants}>About page content</motion.p>
    </motion.div>
  );
}

Conclusion

By following these steps, you’ve successfully added smooth page transitions to your Remix application using Framer Motion. This technique enhances the user experience by providing visual continuity between route changes.

Remember to experiment with different animation variants to find the style that best suits your application’s design and feel. Happy coding!

Send chetoui hamza a reply about this page
More from chetoui hamza
Back to profile