Add page transitions to your Gatsby site.
Allows you to declaratively add page transitions, as well as specify unique transition strategies for any page on an individual basis.
Examples of usage can be found in the Github repository here.
Examples cover:
- Default Transition
- Custom Transition
- No Transition
- Multiple Transitions
-
Install the
gatsby-plugin-page-transitions
plugin:npm install --save gatsby-plugin-page-transitions
or
yarn add gatsby-plugin-page-transitions
- Add into
gatsby-config.js
.
// gatsby-config.js
module.exports = {
plugins: [
'gatsby-plugin-page-transitions'
]
}
- Import
PageTransition
, and wrap the root of each page where transitions are desired with thePageTransition
component
import React from 'react';
import PageTransition from 'gatsby-plugin-page-transitions';
const Index = () => (
<PageTransition>
<div>
<span>Some</span>
<span>Content</span>
<span>Here</span>
</div>
</PageTransition>
)
Pages that are not wrapped with the PageTransition
element navigate immediately, allowing you to decaratively specify which pages has transitions.
If no options are specified, the plugin defaults to:
- Transition time of 250ms. This is the amount of time the browser blocks navigation, waiting for the animation to finish.
- Opacity
ease-in-out
transition from thereact-transition-group
examples, here.
There is a convenience option to let you modify the transition time on the default opacity transitions, like so:
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: 'gatsby-plugin-page-transitions',
options: {
transitionTime: 500
}
}
]
}
If you want to specify your own transition styles when the component enters or leaves, you can do so by passing props into the PageTransition
component.
The component takes in 3 props:
duration
: How long the browser should wait for the animation until navigating. This number should match the CSStransition
time you chose todefaultStyle
: JS style object of what the component looks like defaulttransitionStyles
: Object with keys of the transition states (entering
,entered
,exiting
,exited
) that have JS style objects of the styles of each transition state.
These follow the transitional styling convention from react-transition-group
here.
The plugin is a wrapper around react-transition-group
, so please see their documentation for implementation details.
For an example, if you wanted a transition to:
- Slide in and out from the left
- Lasting 500ms
- Transitions with a cubic-bezier function
Just pass your desired transition down as props into the PageTransition
element.
import React from 'react';
import PageTransition from 'gatsby-plugin-page-transitions';
const Index = () => (
<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}
>
<div>
<span>Some</span>
<span>Content</span>
<span>Here</span>
</div>
</PageTransition>
)
Notice that 500ms
string is specified as the transition length in the JS CSS object. The component needs to be passed 500
in the transitionTime
prop, so the browser can wait for the animation to finish before navigation to the next path.
You can use this method to specify unique transition strategies for each page individually, or wrap PageTransition
yourself for a custom reusable transition.
At a high level the plugin operates this way:
- User clicks a link to another page.
- Page change is caught, and navigation is paused for however long the
transitionTime
is specified. - Page transition event
'gatsby-plugin-page-transition::exit'
is fired. - Rendered components listening to the page transition event plays the transition.
- Pause is released, and browser navigates.
If you require even more control, such as making different elements on the page transition in different ways, you'll need to listen for the page's transition event. Full implementation found in the examples here.
If you are using react-transition-group
's Transition
component as specified here, then your page might generically look something like this:
import React from 'react'
import PageTransition from 'gatsby-plugin-page-transitions'
import Transition from 'react-transition-group/Transition'
const pageTransitionEvent = 'gatsby-plugin-page-transition::exit';
const defaultStyle = {
// Default transition styling
}
const transitionStyles = {
// Transition styling
}
class CustomComponent extends React.Component {
constructor (props) {
super(props)
this.listenHandler = this.listenHandler.bind(this)
this.state = {
in: false
}
}
componentDidMount () {
global.window.addEventListener(pageTransitionEvent, this.listenHandler)
this.setState({
in: true
})
}
listenHandler () {
this.setState({
in: false
})
}
componentWillUnmount () {
global.window.removeEventListener(pageTransitionEvent, this.listenHandler)
}
render () {
return (
<PageTransition transitionTime={500}>
<Transition in={this.state.in} timeout={500}>
{(state) => (
<div style={{
...defaultStyle,
...transitionStyles[state]
}}>
Elements
</div>
)}
</Transition>
</PageTransition>
)
}
}
This component is doing several things:
Per react-transition-group
, there is local state this.state.in
tracking if transitioning elements should be "in" or not
-
this.state.in
begins asfalse
, with elements not "in". -
On mount,
this.state.in
is flipped totrue
, and elements are transitioned in. -
On mount, component begins listening to
gatsby-plugin-page-transition::exit
-
When user navigates away, global window
gatsby-plugin-page-transition::exit
event fires -
<PageTransition transitionTime={500}>
component will handle event by pausing navigation, with an allottedtransitionTime
of 500ms -
Local component
listenHandler
setsthis.state.in
tofalse
, and elements are transitioned out. Transitions should take 500ms or less, if they are to complete before page navigation. -
Transitions complete, page navigates, component cleans up listeners.