This tutorial is out of date and no longer maintained.
Note: This tutorial uses gatsby-plugin-page-transitions
which is not supported in Gatsby 2. You may be interested in gatsby-plugin-transition-link
.
GatsbyJS is a React-based static site generator powered by GraphQL. It makes it possible for you to code and develop your site while Gatsby transforms it into a directory with a single HTML file with all your static assets. On its own, Gatsby is fast and comes preconfigured with service workers, code splitting, server-side rendering, intelligent image loading, asset optimization, and data prefetching.
GatsbyJS, however, does not come with animated page transitions out of the box. In this tutorial, in order to enhance your front-end design capabilities, you will see a few strategies to add page transitions to your GatsbyJS application, such as using a React transition group and using a transition plugin.
To get started with this tutorial, you need preliminary knowledge of React.js. This will help you navigate the code we’ll use here.
If you haven’t already, go ahead and install the Gatsby CLI tool with the following command:
- npm install -g gatsby-cli
With that installed, we can now run Gatsby-specific commands to create, build, and deploy our applications.
To create a new Gatsby project, open a terminal window in your preferred directory and run:
- gatsby new transitions-demo
This will create a new Gatsby project for you. You can navigate into the project folder:
- cd transitions-demo
And run the server command to launch the development server:
- gatsby develop
This will launch the project on localhost:8000
: if you open that up in your browser, you will see your Gatsby project live.
The React transition group is the first and most popular way of adding transitions to Gatsby applications. It is worthy to note this is not an animation library by design, so it doesn’t have the ability to animate styles by itself. Instead, it exposes transition stages, manages classes and group elements, and manipulates the DOM in useful ways, making the implementation of actual visual transitions much easier.
Let’s go ahead and install it and demonstrate how we can leverage it to transition between the pages in our application.
- npm install react-transition-group
It will monitor the entry
and exit
state of elements in the DOM and then apply transitions to them accordingly with respect to our custom transition styles.
The next package we’ll need to install is the Gatsby layout plugin. It gives us the ability to provide a location
property required for transitions to work and injects our layout on every page.
- npm install gatsby-plugin-layout
The first we’ll need to do after installing the dependencies is to configure the gatsby-config.js
file to use the layout we just installed. Open up the file and add the layout plugin in the plugins array:
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
description: `My new Gatsby site`,
author: `@gatsbyjs`,
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-plugin-layout`,
options: {
component: require.resolve(`./src/layouts/index.js`),
},
},
],
}
For this plugin to work correctly, we need to move the layout
file from inside the components
folder to the root of our project src
folder and rename the layout.js
file to index.js
. Then within the components
folder, create a new file called transition.js
to host our transition logic implementations. Once done, our application structure will look more like this:
├── components
├── header.js
├── seo.js
└── transition.js
├── layouts
├── index.js
└── layout.css
└── pages
├── about.js
├── blog.js
├── contact.js
└── index.js
Now let’s go ahead and implement these transitions in our pages. Open the transition.js
file we created in the components
folder and update it with this code:
import React from "react"
import {
TransitionGroup,
Transition as ReactTransition,
} from "react-transition-group"
const timeout = 500
const getTransitionStyles = {
entering: {
position: `absolute`,
opacity: 0,
},
entered: {
transition: `opacity ${timeout}ms ease-in-out`,
opacity: 1,
},
exiting: {
transition: `opacity ${timeout}ms ease-in-out`,
opacity: 0,
},
}
class Transition extends React.PureComponent {
render() {
const { children, location } = this.props
return (
<TransitionGroup>
<ReactTransition
key={location.pathname}
timeout={{
enter: timeout,
exit: timeout,
}}
>
{status => (
<div
style={{
...getTransitionStyles[status],
}}
>
{children}
</div>
)}
</ReactTransition>
</TransitionGroup>
)
}
}
export default Transition
Let’s walk through the code in bits. First, we imported TransitionGroup
, and ReactTransition
from the react-transition-group
package we installed earlier. TransitionGroup
helps us manage the mounting and unmounting of components in the DOM while the ReactTransition
tracks the entry
and exit
states of elements passed to it.
Next, we declared a timeout
variable that will be responsible for our animation durations. We then defined the getTransitionStyles
object that will contain the CSS styles for our animation. Finally, we destructured children
and location
from props for ease of usage.
Notice that ReactTransition
accepts a key (key={location.pathname}
), which is how it tracks the entry and exit of elements in the DOM. With that, we apply the styles depending on the status
of the page/element (entering, exiting, entered) in the DOM.
That’s it for our transition component. The next thing we need to do is to use this component to wrap all our pages. The way it works is that we can wrap all the pages in our application as children
in the layout
component and then wrap the entire layout
component with the transition component.
This way, the location prop we defined in the transition component will take effect and animate our pages accordingly as they enter and exit the DOM. Open the index.js
file in the layouts folder and update it with the code below.
import React from "react"
import PropTypes from "prop-types"
import { StaticQuery, graphql } from "gatsby"
import Header from "../components/header"
import "./layout.css"
import Transition from '../components/transition'
const Layout = ({ children, location }) => (
<StaticQuery
query={graphql`query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}`}
render={data => (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `0px 1.0875rem 1.45rem`,
paddingTop: 0,
}}
>
<Transition location = {location}>
{children}
</Transition>
</div>
</>
)}
/>
)
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default Layout
Here, we imported the Transition
component that we created before, then we used it to wrap the children
, which represents all the pages in our app. We also passed the location
prop to the Transition
component to track the locations of the pages as they enter and exit the DOM.
Finally, let’s modify the index.js
file in our pages
folder to add more pages on the homepage so we can test our transitions. Open it and update it with the following code:
import React from "react"
import { Link } from "gatsby"
import SEO from "../components/seo"
const IndexPage = () => (
<div>
<SEO title="Home" keywords={[`gatsby`, `application`, `react`]} />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<Link to="/blog/">Go to my blog</Link><br />
<Link to="/about/">Go to my about page</Link><br />
<Link to="/contact/">Go to my contact page</Link><br />
</div>
)
export default IndexPage
Now when we run our app, we will see all our pages rendered on the homepage, and when we click on any of them, it will transition into the new page as expected.
The previous step showed one way to transition pages in GatsbyJS. Let’s take a look at an entirely different way to do this with a page transition plugin. The gatsby-plugin-page-transitions
is a plugin that allows you to declaratively add page transitions, as well as specify custom page transitions for any page on your project.
Just like in the last example, we’ll install the necessary dependencies and demonstrate how to add this plugin to our Gatsby app, and use it to transition our application’s pages.
- npm install --save gatsby-plugin-page-transitions
Having installed the plugin, let’s add it to our project through the Gatsby config file in the root of our project. Open the gatsby-config.js
file and update the plugins array with the following code:
plugins: [
`gatsby-plugin-react-helmet`,
`gatsby-plugin-page-transitions`,
{
resolve: 'gatsby-plugin-page-transitions',
options: {
transitionTime: 500
}
}
]
The gatsby-plugin-page-transitions
plugin provides us with different transition types. There are:
Let’s start with the default transition, which is actually the same as what we saw in the last example. To get this transition working in our pages, wrap all the pages where we need the transition with the plugin.
To demonstrate this, let’s import the plugin into our Index page and a few other pages in our app, then run the app.
import React from "react"
import { Link } from "gatsby"
import SEO from "../components/seo"
import PageTransition from 'gatsby-plugin-page-transitions';
const IndexPage = () => (
<PageTransition>
<SEO title="Home" keywords={[`gatsby`, `application`, `react`]} />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<Link to="/blog/">Go to my blog</Link><br />
<Link to="/about/">Go to my about page</Link><br />
<Link to="/contact/">Go to my contact page</Link><br />
</PageTransition>
)
export default IndexPage
Now when we run the app, we get exactly the same transitions we had in our last example, since we are using the same transition time of 500ms.
You can set your preferred transition duration for your transitions; the higher the number you set, the slower the transition speed.
The custom transition type gives you the flexibility to determine how you want your pages to transition. The default transition style only performs a kind of reveal animation to transition in any new page. However, there’s so much more you can do with the plugin. For instance, you can decide to transition-in pages from the side of the browser or from the top, zoom pages in and out, swirl pages across the screen, and more.
To do this, you define your custom transition styles with CSS and pass it into the PageTransition
element as a prop. Here’s how we can change the default transition behavior in the Index and About pages to a custom sliding transition.
import React from "react"
import { Link } from "gatsby"
import SEO from "../components/seo"
import PageTransition from 'gatsby-plugin-page-transitions';
const IndexPage = () => (
<PageTransition
defaultStyle={{
transition: 'left 500ms cubic-bezier(0.47, 0, 0.75, 0.72)',
left: '100%',
position: 'absolute',
width: '100%',
}}
transitionStyles={{
entering: { left: '0%' },
entered: { left: '0%' },
exiting: { left: '100%' },
}}
transitionTime={500}
>
<SEO title="Home" keywords={[`gatsby`, `application`, `react`]} />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<Link to="/blog/">Go to my blog</Link><br />
<Link to="/about/">Go to my about page</Link><br />
<Link to="/contact/">Go to my contact page</Link><br />
</PageTransition>
)
export default IndexPage
Make the same update in your about
page and run the app again. We should now get the slide transitions working in both pages.
You can also have more than one transition type in your projects. You can have a different transition for every single page in your app if you so please. The only concern here is that sometimes too many transition types can negatively impact user experience.
If you decide to implement different transitions in different pages, style your PageTransition
elements separately and you’ll have different transitions for different pages.
If your application’s pages are filled with content that will require your users to scroll all the way down to the bottom of your pages, you may experience some weird behaviors when your pages transition in and out. This is because, by default, when there are enough elements on the page, it jumps to the top of the page first before triggering transitions.
To fix this, we can set a time out for the transition so it can wait for the transition to be executed before the page scrolls to the top. Open the gatsby-browser.js
file in the application’s root directory and update it with this code:
const transitionDelay = 500
exports.shouldUpdateScroll = ({
routerProps: { location },
getSavedScrollPosition,
}) => {
if (location.action === 'PUSH') {
window.setTimeout(() => window.scrollTo(0, 0), transitionDelay)
} else {
const savedPosition = getSavedScrollPosition(location)
window.setTimeout(
() => window.scrollTo(...(savedPosition || [0, 0])),
transitionDelay
)
}
return false
}
In this tutorial, we have gone through the various ways you can implement page transitions in your Gatsby projects. In the process, we looked at how to set up a new Gatsby project from scratch, how to install the necessary dependencies for the transitions, and how to use them to build pages.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
This looks clever and works, but overall I can’t shake the feeling of going back into 1999, when the markup and presentation logic were jumbled together, over time degrading into an incomprehensible spaghetti.
Hello, and thanks for this article!
gatsby-plugin-page-transitions
doesn’t work on Gatsby v2 because of some changes in the API, as the creator now states in the plugin readme.