This tutorial assumes that you're already familiar with next.js and just what to add transitions to your pages and that you're have hope of using typescript
Step 1
Install required dependency
$ npm install react-transition-group
if you're using Typescript
install the types for it
$ npm install -D @types/react-transition-group
Step 2
create a Transition.tsx
component in the component folder
import {
TransitionGroup,
Transition as ReactTransition,
} from "react-transition-group"
import { ReactChild } from "react"
type TransitionKind<RC> = {
children: RC
location: string
}
const TIMEOUT: number = 200
const getTransitionStyles = {
entering: {
position: `absolute`,
opacity: 0,
transform: `translateX(50px)`,
},
entered: {
transition: `opacity ${TIMEOUT}ms ease-in-out, transform ${TIMEOUT}ms ease-in-out`,
opacity: 1,
transform: `translateX(0px)`,
animation: "blink .3s linear 2",
},
exiting: {
transition: `opacity ${TIMEOUT}ms ease-in-out, transform ${TIMEOUT}ms ease-in-out`,
opacity: 0,
transform: `translateX(-50px)`,
},
}
const Transition: React.FC<TransitionKind<ReactChild>> = ({
children,
location,
}) => {
return (
<TransitionGroup style={{ position: "relative" }}>
<ReactTransition
key={location}
timeout={{
enter: TIMEOUT,
exit: TIMEOUT,
}}
>
{(status) => (
<div
style={{
...getTransitionStyles[status],
}}
>
{children}
</div>
)}
</ReactTransition>
</TransitionGroup>
)
}
export default Transition
Step 3
Next, import this Transition.tsx
component to your layouts/MainLayout
or _app.tsx
if you're doing this in the _app.tsx be sure to replace children
with <Component {...pageProps} />
.
We have imported useRouter
from next//router
and passed the pathname to location props
// import this `Transition.tsx` component to your `layouts/MainLayout` or `_app.tsx`
import React, { Fragment } from "react"
import Transition from "../components/Transition"
import { useRouter } from "next/router"
const MainLaylout: React.FC = () => {
const router = useRouter()
return (
// you may import your header and footer here too
<Fragment>
<Transition location={router.pathname}>
<div className="min-h-screen">{children}</div>
</Transition>
</Fragment>
)
}
// React.memo may not be important
export default React.memo(MainLaylout)
Step 4
Now you have everything ready it's time to use the MainLayout
in our pages
..
to use the layout, import and wrap your pages with MainLayout
for example
import React, { Fragment } from "react"
// path to your main layout
import MainLayout from "layouts/MainLayout"
const IndexPage: React.FC = (props) => {
return (
<MainLayout>
<div> replace with your content here..</div>
</MainLayout>
)
}
export default React.memo(IndexPage)
Wrap each of your pages with the main layout, congratulations, you've just added page transitions to a nextjs app
Top comments (4)
This is really cool. I need to dig a bit into this, as I do not get any page-transitions between pages when transitioning between pages build on the same page-file but on different routes. But this is a really solid starting point and a lot lighter on bundle size compared to something like Framer. Thanks for the article - it really helped a lot!
Small follow up if anyone is facing a similar issue:
router.pathname is the path to the page-file. So when you pass routher.pathname as a prop to the Transition component you will only get a transition when you navigate to a page that is based on another page-file. This will probably work fine in most instances, but if you use a CMS for content (my current project uses headless WordPress) you could be using the same file ( e.g. page/[...page].tsx ) to generate a lot of different pages.
The workaround is to pass router.asPath instead. This way you will get a transition every time the page is navigated to a different url.
Awesome bro, you saved my day !
it works fine now,
looking forward for your next tutorials.
Not working if the page has serverSideProps 🤷♂️ Any idea to make this work?