React. How to animate transitions between React Router routes
Learn how to create animations when navigating between routes using React Router
In this article I want to talk to you about how we can animate the transitions between the routes of our application when we work with React Router, one of the main libraries that we have within the React ecosystem to define a routing system.
The idea will be to use the React Transition Group library in order to define these animations (which we will create using basic CSS) which will help us to get acquainted with its basic concepts while also delving into some very interesting React Router features.
So, without entertaining ourselves, let’s do it!
Basic animation with React Transition Group
If you have never worked with this library I think that the most interesting thing to internalize its operation will be to see a simple example. To do this, I will start from a previous article in which I explained how we can use the React Portals API to create a modal window in our application.
In this article I created a repository with the final code that will be the one we will use as a starting point to add an animation to the modal window when it is displayed.
So first we will install the React Transition Group library:
yarn add react-transition-group
If you have seen, the code responsible for creating the portal associated with our modality is as follows:

The idea will now be to add a transition to the <div class="modal-dialog>
so that the modal window is shown from top to bottom.
So what we will do is wrap it using the CSSTransition component provided by the React Transition Group library.

Let’s see what each of the attributes we have added means:
- appear indicates that, although the component is already showing when the
CSSTransition
component is mounted, the animation also takes place, since the default behavior is not to execute it if the component to animate is already being displayed. In our example we set it to true to force this behavior. - in allows us to show or hide the component to animate. In our example we set it to
true
since the modal is already showing once the portal has been created. - classNames allows us to define the prefix of the classes that the CSSTransition component will add to the component to animate. They are the following:
.modal-transition-enter {
}.modal-transition-enter-active {
}.modal-transition-exit {}.modal-transition-exit-active {}.modal-transition-appear {}.modal-transition-appear-active {}
- timeout, to define the duration of the transition in milliseconds.
Once this is done, what we will do is define the CSS associated with the transition based on the classes that CSSTransition. In our case it will be the following:

In our case the CSS code is very simple. Basically we define the modal-transition-appear
class to define the duration of the transition and initially the modal moves -100% upwards so that, when the CSSTransition component adds the modal-transition-appear-active
class the modal is scroll down using: transform: translateY(0)
.
With this we have already achieved what we wanted 🎉🎉🎉:
Animating transitions between React Router routes
Once we understand the basic operation of the CSSTransition component, what we will do is apply a similar logic to animate the transitions between the different routes of our application when we work with React Router.
But before I start, I want to tell you some interesting things about how the React Transition Group library works.
💡 React Transition Group
In addition to the CSSTransition component, the React Transition Group library provides us with the TransitionGroup component that allows us to animate a list of items.
Thus, when we wrap a list of items that we want to animate with the <TransitionGroup>
component, it tracks each item in the list using the key
property. That is, <TransitionGroup>
has an internal state where it stores who its child components are, so when a change occurs, it can determine which elements are entering and which ones are leaving and renderer them with their respective classes (*-appear
, *-enter
, and *-exit
from the previous example) to animate them.
For example, if initially within a <TransitionGroup>
we have the following:
<TransitionGroup>
<CSSTransition key="first" ...>
<Item/>
</CSSTransition>
</TransitionGroup>
and suddenly we change to:
<TransitionGroup>
<CSSTransition key="second" ...>
<Item/>
</CSSTransition>
</TransitionGroup>
There will be a time when <TransitionGroup>
will be rendering the following:
<TransitionGroup>// saliendo
<CSSTransition key="first" ...>
<Item/>
</CSSTransition>// entrando
<CSSTransition key="second" ...>
<Item/>
</CSSTransition>
</TransitionGroup>
Allowing us to make animations between several elements.
💡 Basic concepts to animate React Router
As you know, the React Router Route
and Switch
components use a property called location
to determine which route we have matched with the current browser route. This property is extracted by default from the React Router context
object and is a “live” object, that is, it is updated as the user navigates.
However, this behavior, as we will see later, has a problem when we have routes that “enter” and routes that “leave”, since the latter will no longer match and therefore will not be painted. Luckily there are ways to skip this limitation.
The first thing to keep in mind is that the element we will animate will be the <Switch>
component of React Router and not the Route
component itself.
That is, we will not have this:
<Switch>
<TransitionGroup>
<CSSTransition>
<Route path='/first'><FirstComponent /></Route>
<Route path='/second'><SecondComponent /></Route>
...
</CSSTransition>
</TransitionGroup>
</Switch>
but this:
<TransitionGroup>
<CSSTransition>
<Switch>
<Route path='/first'><FirstComponent /></Route>
<Route path='/second'><SecondComponent /></Route>
</Switch>
</CSSTransition>
</TransitionGroup>
Thus, following the logic of the <TransitionGroup>
component that I mentioned before, during the animation the DOM will have the following:
<TransitionGroup>// saliendo
<CSSTransition>
<Switch>
<Route path='/first'><FirstComponent /></Route>
<Route path='/second'><SecondComponent /></Route>
</Switch>
</CSSTransition>// entrando
<CSSTransition>
<Switch>
<Route path='/first'><FirstComponent /></Route>
<Route path='/second'><SecondComponent /></Route>
</Switch>
</CSSTransition>
</TransitionGroup>
🔛 Creating a basic transition for React Router
With all the above concepts we can already define a component called <AnimatedSwitch>
that allows us to make a simple animation between our routes:
const AnimatedSwitch = withRouter(({ location }) => (
<TransitionGroup>
<CSSTransition
key={location.key}
classNames="slide"
timeout={1000}
>
<Switch>
<Route path='/first' component={First} />
<Route path='/second' component={Second} />
</Switch>
</CSSTransition>
</TransitionGroup>
));
As we mentioned before, we are defining a key
property for the CSSTransition
component so that the TransitionGroup
component can keep track of which Switch
enters and which leaves.
To define this key
we will use the React Router location
object, which we can access using the HOC withRouter
.
Let’s see what we have achieved:
Wow … It doesn’t seem to work quite well. We have achieved the animation but the route that comes out is the same as the one we are going to instead of the behavior we would expect
Why is this?
Well, this is because by default <Switch>
is working with the React Router context location
object, which, if you remember what was said before, is a living object that changes as the user navigates.
So, if we navigate for example from /
to/first
what will happen is the following:
<TransitionGroup> // exiting
<CSSTransition> // The exiting Switch is taking the object location
// from the context, so
// location.path = '/first'
<Switch>
<Route path='/'><HomeComponent /></Route>
<Route path='/first'><FirstComponent /></Route>
<Route path='/second'><SecondComponent /></Route>
</Switch>
</CSSTransition> // entering
<CSSTransition> // The entering Switch is also taking the object location
// from the context, so
// location.path = '/first'
<Switch>
<Route path='/'><HomeComponent /></Route>
<Route path='/first'><FirstComponent /></Route>
<Route path='/second'><SecondComponent /></Route>
</Switch>
</CSSTransition>
</TransitionGroup>
How can we force the Switch that leaves to pick up the “previous” location object while the one that enters takes the location object with the path to which we are heading?
Well, in a much easier way than we might think, since the Switch
component admits that we pass a location
property with the object so that instead of using the live location
object from the context, take the object that we are passing it. In this way, we can rewrite our AnimatedSwitch
component by adding the following:
const AnimatedSwitch = withRouter(({ location }) => (
<TransitionGroup>
<CSSTransition
key={location.key}
classNames="slide"
timeout={1000}
>
<Switch location={location}>
<Route path='/first' component={First} />
<Route path='/second' component={Second} />
</Switch>
</CSSTransition>
</TransitionGroup>
));
That is, to the Switch
component we are passing the immutable location
object from the HOC withRouter
, so that when the transition from the route /
to the route /first
occurs, what will be renderer within the TransitionGroup
component will be the following:
<TransitionGroup>// saliendo
<CSSTransition>// El Switch que sale está cogiendo el objeto location
// procedente del HOC withRouter, el cual es inmutable y por
// tanto, location.path = '/'
<Switch>
<Route path='/'><HomeComponent /></Route>
<Route path='/first'><FirstComponent /></Route>
<Route path='/second'><SecondComponent /></Route>
</Switch>
</CSSTransition>// entrando
<CSSTransition>// El Switch que entra también está cogiendo el objeto location
// del HOC withRouter, que ahora contendrá la información
// actualizada con la ruta hacia la que nos dirigimos, es decir
// location.path = 'first'
<Switch>
<Route path='/'><HomeComponent /></Route>
<Route path='/first'><FirstComponent /></Route>
<Route path='/second'><SecondComponent /></Route>
</Switch>
</CSSTransition>
</TransitionGroup>
And with this we will have our brand new animation working correctly:
Final thoughts
As you can see, creating an animation for the transitions between our routes is relatively simple if we know how the React Router and React Transition Group libraries work.
However, our example has a limitation: is it true that when we go to the right, the animation goes one way and when we turn the animation back on the opposite?
Well, this behavior requires an extra dose of effort (not much, promised 😊😊😊) that I will tell you in the following article.
I hope this has helped you to familiarize yourself with the React Transition Group bookstore and that it helps you to give a little life to your applications made with React.
Here you have the second part of this article:
References
Do you want to read more articles like this?
If you liked this article I encourage you to subscribe to the newsletter that I send every Sunday with similar publications to this and more recommended content: 👇👇👇