npm i @mesqueeb/react-page-transition
A React component that makes it easy to use the page transitions from the Codedrops Page Transitions Demo. See original demo: tympanus.net/Development/PageTransitions/.
Many thanks to @steveeeie for spearheading combining react-router with react-transition-group.
I've started from a base of steveeeie but ended up completely rewriting all the code from scratch to make sure of the following support and improvements:
React support:
- β Vite + React 18 + react-router (aka react-router-dom) v6
- β Vite + React 18 + react-router (aka react-router-dom) v5
- β Vite + React 18 + @reach/router (works but with caveats, see below)
Features:
- β
This is a CSS based implementation, where it relies on a
page-transition-
classes (you can bring your own animations) - β Page transitions are queued so rapidly changing the route will animate all transitions in order with their respective durations and animations.
- β Support for Vite & react-router v6
- β Monorepo hosts all demo apps to easily verify version support
- β The reactJS official react-transition-group as only dependency
- β ESM only, to help move the industry forward
npm i @mesqueeb/react-page-transition
npm i react-router-dom@^6.30.1
The following is a minimal example of how to use PageTransition
with react-router
v6.
import '@mesqueeb/react-page-transition/animations.css'
import { PageTransition } from '@mesqueeb/react-page-transition'
import { BrowserRouter, Link, Route, Routes, useLocation } from 'react-router-dom'
function RoutesWrapper() {
const location = useLocation()
return (
<PageTransition preset="moveToLeftFromRight" transitionKey={location?.pathname} className="fullscreen" contentClassName="fullscreen">
<Routes location={location}>
<Route
path="/"
element={
<div className="fullscreen" style={{ background: 'goldenrod' }}>
<h1>Home</h1>
</div>
}
/>
<Route
path="/about"
element={
<div className="fullscreen" style={{ background: 'lightseagreen' }}>
<h1>About</h1>
</div>
}
/>
</Routes>
</PageTransition>
)
}
function App() {
return (
<>
<style lang="css">{globalStyles}</style>
<BrowserRouter>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<RoutesWrapper />
</BrowserRouter>
</>
)
}
/** Global styles defined here just to keep the example self-contained */
const globalStyles = `
html, body, #root {
margin: 0;
width: 100dvw;
height: 100dvh;
display: flex;
flex-direction: column;
align-items: stretch;
}
.fullscreen {
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
}
`
export default App
Wrap your routes inside the PageTransition
component and pass one of the preset names to the preset
prop. View the presets for the full list of presets.
You will also need to pass the current location.path
to the transitionKey
prop, this is so that the internal TransitionGroup
can track which components are entering and exiting.
PageTransition
is styled with height: 100%
, so the parent containers need to be given a height for it to render correctly. In this code example we use height: 100dvh
. If you have extra div layers, make sure they grow to their parent height.
Not recommended, as @reach/router
technically doesn't support React v18, but I did manage to make it work...
npm i @mesqueeb/react-page-transition
npm i @reach/router --force # because npm says it's not compatible with React v18
For the code example see demo-reach-router for the minimal implementation. And remember to not use StrictMode
anywhere, as that breaks @reach/router
completely.
The available presets are all those from the original Codrops demo. You can choose a preset by passing it to the preset
prop, like so:
<PageTransition preset="moveToLeftFromRight">
Some of my favourites:
export type PresetId = 'fall' | 'newspaper' | 'moveToLeftFromRight' | 'moveToRightFromLeft' | 'slide' | 'cubeToLeft' | 'cubeToRight'
// and many more
Full list available at presets.
I added four new presets as well:
;'slideOverToLeftFromRight' | 'slideOverToRightFromLeft' | 'slideOverToTopFromBottom' | 'slideOverToBottomFromTop'
And you can bring your own.
If you look at the animations.css file you'll see the css defined for the transitions as per the original Codrops demo. You can copy some of the definitions and tweak them to your liking. Make sure those styles are somewhere available in your app's stylesheets.
@keyframes myAnimationToLeft { from { } to { transform: translateX(-100%) }/* tweak these */ } .page-transition-myAnimationToLeft { animation: moveToLeft .6s ease both }
@keyframes myAnimationFromLeft { from { transform: translateX(-100%) } /* tweak these */ } .page-transition-myAnimationFromLeft { animation: moveFromLeft .6s ease both }
@keyframes myAnimationToRight { from { } to { transform: translateX(100%) } /* tweak these */ } .page-transition-myAnimationToRight { animation: moveToRight .6s ease both }
@keyframes myAnimationFromRight { from { transform: translateX(100%) } /* tweak these */ } .page-transition-myAnimationFromRight { animation: moveFromRight .6s ease both }
Then you would run the transition like so:
<PageTransition
preset={{
exit: { name: 'myAnimationToLeft' },
enter: { name: 'myAnimationFromLeft', delay: 100, onTop: true }
}}
transitionKey={location?.pathname}
className="fullscreen"
contentClassName="fullscreen"
>
<Routes location={location}>{/* ... */}</Routes>
</PageTransition>
The fullscreen classes are optional and do not come bundled with this package, so if you need to make the page transition fullscreen, you'll need to define them yourself.
The preset
prop is typed as follows:
export type AnimationMeta = {
name: AnimationName
delay?: number
onTop?: boolean
}
export type Preset = {
exit: AnimationMeta
enter: AnimationMeta
}
It's easy to open and play with the demo app(s):
git clone https://github.com/mesqueeb/react-page-transition.git
npm i
# then you can run the demo with:
npm run dev:demo-react-router-v6-advanced
There are also other demos for version support testing:
npm run dev:demo-react-router-v6
npm run dev:demo-react-router-v5
npm run dev:demo-reach-router
WWWWWW||WWWWWW
W W W||W W W
||
( OO )__________
/ | \
/o o| MIT \
\___/||_||__||_|| *
|| || || ||
_||_|| _||_||
(__|__|(__|__|