I’m adding page transitions to a Gatsby site I’m working on using the framer-motion library. Currently, it works great on my local setup, but when I push to production, the exit animation no longer fires.
I’m wrapping my pages in the AnimatePresence component using gatsby-browser.js:
import React from 'react';
import {motion, AnimatePresence} from 'framer-motion';
export const wrapPageElement = ({element}) => (
<AnimatePresence exitBeforeEnter>{element}</AnimatePresence>
);
And then have a motion.main component around the page content in my layout.js file:
/** @jsx jsx */
import * as React from "react"
import { Global } from "@emotion/react"
import { Box, Container, jsx } from "theme-ui"
import Seo from "./seo"
import Header from "./header"
import Footer from "./footer"
import CodeStyles from "../styles/code"
import SkipNavLink from "./skip-nav"
import { motion, AnimatePresence } from 'framer-motion'
type LayoutProps = { children: React.ReactNode; className?: string }
const Layout = ({ children, className = `` }: LayoutProps) => (
<React.Fragment>
<Global
styles={(theme) => ({
"*": {
boxSizing: `inherit`,
},
html: {
WebkitTextSizeAdjust: `100%`,
},
img: {
borderStyle: `none`,
},
pre: {
fontFamily: `monospace`,
fontSize: `1em`,
},
"[hidden]": {
display: `none`,
},
"::selection": {
backgroundColor: theme.colors.text,
color: theme.colors.background,
},
a: {
transition: `all 0.3s ease-in-out`,
color: `text`,
},
})}
/>
<Seo />
<SkipNavLink>Skip to content</SkipNavLink>
<Container>
<Header />
<motion.main
key={location.pathname}
initial={{ opacity: 0, y: 2.5 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -2.5 }}
transition={{
type: "spring",
damping: 8,
mass: .6,
stiffness: 70,
}}
>
<Box id="skip-nav" sx={{ ...CodeStyles }} className={className}>
{children}
</Box>
</motion.main>
<Footer />
</Container>
</React.Fragment>
)
export default Layout
Does anyone have ideas as to why this might not be working when I deploy? (FYI I am using Netlify). I’ve tried many different semantic variations of this idea to no avail. Could it be how I’m declaring the key for the motion component? How I’m wrapping the AnimatePresence and motion components?
2
Answers
Try making motion.main a direct descendent of AnimatePresence.
E.g.
This is written in the docs. Probably because there are too many wrappers before your
motion.main
component.wrapPageElement
is a shared API between Gatsby Browser (gatsby-browser.js
) and Gatsby SSR (gatsby-ssr.js
). Try adding the same wrapping component in thegatsby-ssr.js
:In the docs:
The fact that works in the local environment and not in Netlify leads me to think that you can potentially have mismatching Node versions between both environments, causing a different dependency tree. If building the site locally makes your animation work, the issue is on Netlify’s side (or in the Node versions installed, configuration). If the local built site doesn’t (same behavior as Netlify’s) the issue is on your code.
You can try setting in both environments the same Node version. To do so automatically, you can run:
This will create a
.nvmrc
file containing the Node version (node -v
). When Netlify finds this file at the root of your project, it uses the Node version as a base for installing the dependencies (docs: https://docs.netlify.com/configure-builds/manage-dependencies/#node-js-and-javascript)Try both workarounds and see how’s the debugging. As I said, if both environments has the exact same configuration the built shouldn’t work either locally so the issue should be in your code (missing
wrapPageElement
wrapping ingatsby-ssr.js
, etc).