How to Animate Components' Entrance and Exit in React
Tags: react, javascript, tutorial
Published: 2021-10-21 15:18:21

---
title: How to Animate Components' Entrance and Exit in React
published: true
date: 2021-10-21 10:26:43 UTC
tags: React,Javascript,tutorial
canonical_url: https://blog.shahednasser.com/how-to-animate-components-entrance-and-exit-in-react/
cover_image: https://blog.shahednasser.com/static/68d609af4788e9d314c4a78cf0c7f662/sebastian-svenson-d2w-_1LJioQ-unsplash.jpg
---

_This article was originally published on [my personal blog](https://blog.shahednasser.com/how-to-animate-components-entrance-and-exit-in-react/)_

Say you have a list component in React where the user can add or remove items in the list. It would be nice to animate the items as they are being added or removed from the list.

In this tutorial, we'll cover how to animate components' entrance and exit in React using [React Transition Group](http://reactcommunity.org/react-transition-group/).

You can find the full code for this tutorial in [this GitHub Repository](https://github.com/shahednasser/react-transition-group-tutorial), and you can see a [working demo](https://react-transition-group-tutorial.netlify.app).

## What is React Transition Group

React Transition Group is a library that allows you to add animation on a component or multiple components' entrance and exit.

React Transition Group does NOT do the animation for you, that is it does not provide the animation. It facilitates adding the animation either through CSS classes or styles when a component enters or exits.

React Transition Group exposes the components that will allow you to easily do that. There are 4 components that it exposes: [Transition](http://reactcommunity.org/react-transition-group/transition), [CSSTransition](http://reactcommunity.org/react-transition-group/css-transition), [SwitchTransition](http://reactcommunity.org/react-transition-group/switch-transition), and [TransitionGroup](http://reactcommunity.org/react-transition-group/transition-group).

We'll go over different use cases when it comes to animating elements, and in each use case which component you should use and how you can use them.

## Animating a Single Element

The first use case we'll look at is animating a single element. Let's say we have an element that we want to animate every time it enters or exits.

There are 2 components we can use: `Transition` and `CSSTransition`. The recommended component is `CSSTransition`, but we'll cover both.

### Using Transition

With the `Transition` component, you can add CSS styling based on the different states. This component covers the states:

1. `entering`: Before the element enters.
2. `entered`: Element has entered.
3. `exiting`: Before the element exits
4. `exited`: The element has exited.

Generally, `CSSTransition` is recommended to be used instead of `Transition`. `Transition` is provided as a platform-agnostic base component.

For this example, we'll have a button that will allow us to show or hide a picture of a cat. First, we need to create a state variable to store and indicate whether the image should be shown or not.

```
const [transitionState, setTransitionState] = useState(false)
```

Then, We'll use the `Transition` component to wrap the `img` element. The `Transition` component takes the prop `in` which is a boolean variable that indicates whether the component should enter or not. We should pass the state variable to this prop.

Another required prop that `Transition` accepts is `timeout` which defines the duration of the animation.

```
<Transition in={transitionState} timeout={300} >
...
</Transition
```

Inside `Transition`, a function is passed which receives the `state` parameter. This parameter indicates the current state of the component, which will be one of the 4 states mentioned earlier.

Using that `state` variable we can change the CSS styling of the component to animate it.

So, we need to create an object that holds the stylings we want to apply:

```
const transitions = {
  entering: {
    display: 'block'
  },
  entered: {
    opacity: 1,
    display: 'block'
  },
  exiting: {
    opacity: 0,
    display: 'block'
  },
  exited: {
    opacity: '0',
    display: 'none'
  }
};
```

Notice how we set the object keys or properties as the name of the states.

Then, in the child function of `Transition`, we set the style based on the current state:

```
<Transition in={transitionState} timeout={300} >
	{state => (
		<img src="https://cataas.com/cat" alt="Cat" style={{
			transition: 'all .1s',
			opacity: 0,
			display: 'none',
			...transitions[state]
			}} className="mt-2" />
	)}
</Transition>
```

Notice how the function returns the `img` element. Inside the `style` prop of the `img` element we first set the default styling, then we add the styling based on the state using this line:

```
...transitions[state]
```

Now, everytime the state changes when the component enters or exits, the `state` variable in the child function will change. So, the styling of the element will change based on the value of the `state` variable, which will add animation to the element.

Also, the image we're using is from [Cat as a service](https://cataas.com/#/).

The only thing left is to add a button to toggle the state variable `transitionState` to show and hide the image:

```
<Button onClick={() => setTransitionState(!transitionState)}>{transitionState ? 'Hide' : 'Show'} Cat</Button>
```

### Using CSSTransition

The recommended approach for this use case is using `CSSTransition`. The `CSSTransition` component allows you to add classes for each state, which gives you more freedom to add animation to your components.

To make the animation easier we'll use [Animate.css](https://animate.style) which is a CSS animation library that provides us with many animations we can easily use.

To animate an element with `CSSTransition`, you wrap it within the `CSSTransition` component. Similar to `Transition` `CSSTransition` receives the `in` prop which indicates whether the component should enter or exit. Also, it accepts the `timeout` prop which determines the duration of the animation.

Unlike `Transition`, `CSSTransition` receives the prop `classNames` which allows us to define the classes that should be added based on the different states.

`classNames` can be an object or a string. If a string is passed, the class will be used as a prefix for the different states. For example, if you pass to `classNames` "fade", the class `fade-enter` will be added to the component when it enters. When the component exits, the class `fade-exit` is added. The same goes for the rest of the states.

If an object is passed as the value for `classNames`, then the keys or properties should be the name of the state, and the value should be the class to apply for that state. For example:

```
classNames={{
 appear: 'fade-in',
 appearActive: 'fade-in-active',
 appearDone: 'fade-in-appeared',
 enter: 'fade-in-enter',
 enterActive: 'fade-in-enter-active',
 enterDone: 'fade-in-done',
 exit: 'fade-out',
 exitActive: 'fade-out-active',
 exitDone: 'fade-out-active',
}}
```

Notice that you don't need to add class names for all these states. This just gives you more freedom and flexibility over it. Generally, you should set the class that you want to apply when the element enters to `enterActive`, and the class that you want to apply when the element exits to `exitActive`. Basically, the `active` phase of each state is when you should apply the animation.

So, back to our example, we want to animate an image of a cat as it is toggled by a button. First, we'll add 2 state variables:

```
const [showCat, setShowCat] = useState(false);
const [imageClasses, setImageClasses] = useState("d-none");
```

`showCat` will be used for the `in` prop to determine when the element should enter and exit. As for `imageClasses`, we'll get to why we need it later on.

Next, we'll add the `CSSTransition` component:

```
<CSSTransition in={showCat} timeout={500} classNames={{
          enterActive: 'animate__bounceIn',
          exitActive: 'animate__bounceOut'
        }} 
        onEnter={showImage}
        onEntered={removeOpacity}
        onExited={hideImage}
        className={`animate__animated my-4 ${imageClasses}`}>
...
</CSSTransition>
```

Notice the following:

1. On `enterActive`, which is when the element should appear, we add the class `animate __bounceIn`, and on `exitActive`, which is when the element should exit, we add the class `animate__ bounceOut`. Both these classes are from the Animate.css library.
2. We have added a listener for `onEnter`, which will be triggered when the element enters; a listener for `onEntered`, which will be triggered when the element has finished entering; a listener for `onExited` which will be triggered when the element has exited. We'll implement these listeners in a bit.
3. We have passed a `className` prop that would add default classes to the child component.

As you can see, we're using the state variable `imageClasses` inside the string passed to `className`. When using `CSSTransition`, you'll assume that the exit state will be applied initially when the initial value passed to `in` is false. That's actually not true. Initially, if the value of the `in` prop is false, no classes are added.

As we don't want the image to be initially visible, we're using a state variable to add the Bootstrap class `d-none` as we're using it in our project. This class will hide the element when added.

And this is why we added the event listeners. We'll change the value of `imageClasses` based on each state:

```
function hideImage() {
	setImageClasses("d-none");
}

function showImage(node) {
    setImageClasses("d-block");
    node.style.opacity = 0;
}

function removeOpacity (node) {
    node.style.opacity = 1;
}
```

Inside `CSSTransition` we add the element we want to animate:

```
<CSSTransition in={showCat} timeout={500} classNames={{
          enterActive: 'animate__bounceIn',
          exitActive: 'animate__bounceOut'
        }} 
        onEnter={showImage}
        onEntered={removeOpacity}
        onExited={hideImage}
        className={`animate__animated my-4 ${imageClasses}`}>
	<img src="https://cataas.com/cat" alt="Cat" />
</CSSTransition>
```

That's it! The only thing left is to add the button to toggle the `showCat` state variable:

```
<Button onClick={() => setShowCat(!showCat)}>{showCat ? 'Hide' : 'Show'} Cat</Button>
```

Now, every time you click the button the classes will change based on the state.

## Animate a Group of Element

This applies to the first example mentioned in this article. Let's say you have a list and you want to animate whenever an element is added or removed from it. The elements will generally be dynamic, so you can't use `CSSTransition` or `Transition` on them one by one.

### Using TransitionGroup

The component `TransitionGroup` wraps a list of `CSSTransition` or `Transition` components and manages their animation based on their states. In a use case where the list of elements to be added is dynamic, it's useful to use this component.

You pass `CSSTransition` or `Transition` components as children. There's no need to pass props to `TransitionGroup`, as the configuration for the animation is done through the props passed to the children components.

In this example, we'll have an array of 4 elements in the beginning. Then, the user can add an item by clicking on a button or removing an item by clicking on the X icon.

![How to Animate Components' Entrance and Exit in React](https://backend.shahednasser.com/content/images/2021/10/Screen-Shot-2021-10-21-at-12.18.50-PM.png)

To make the implementation easier, we'll have an array of languages to add items from it randomly:

```
const defaultLanguages = [
  {
    id: 1,
    name: 'Java'
  },
  {
    id: 2,
    name: 'JavaScript'
  },
  {
    id: 3,
    name: 'PHP'
  },
  {
    id: 4,
    name: 'CSS'
  },
  {
    id: 5,
    name: 'C'
  },
  {
    id: 6,
    name: 'C#'
  },
  {
    id: 7,
    name: 'HTML'
  },
  {
    id: 8,
    name: 'Kotlin'
  },
  {
    id: 9,
    name: 'TypeScript'
  },
  {
    id: 10,
    name: 'Swift'
  }
];
```

And we'll use a one-liner function from [1Loc](https://1loc.dev) to get random elements from an array:

```
const randomItems = (arr, count) => arr.concat().reduce((p, _, __, arr) => (p[0] < count ? [p[0] + 1, p[1].concat(arr.splice((Math.random() * arr.length) | 0, 1))] : p), [0, []])[1];
```

Then, we'll define a state variable which will be the array of languages we'll show the user in a list:

```
const [languages, setLanguages] = useState(randomItems(defaultLanguages, 4));
const [counter, setCounter] = useState(11);
```

We also define a state variable `counter` which we'll use to change the `id` property from the `defaultLanguages` array when adding a new item to the `languages` array. This is just to ensure that the IDs are unique when we are choosing random items from the array.

Then, we render a `TransitionGroup` component and inside it we loop over the `languages` state variable and render a `CSSTransition` component for that variable:

```
<TransitionGroup>
	{languages.map(({id, name}) => (
		<CSSTransition key={id} classNames={{
                enterActive: 'animate __animated animate__ lightSpeedInLeft',
                exitActive: 'animate __animated animate__ lightSpeedOutLeft'
              }} timeout={900}>
			<li className="p-3 border mb-3 shadow-sm rounded border-info d-flex justify-content-between">
				<span>{name}</span>
                <CloseButton onClick={() => removeLanguage(id)}></CloseButton>
             </li>
			</CSSTransition>
	))}
</TransitionGroup>
```

Notice that we're passing the class `animate __animated animate__ lightSpeedInLeft` for the state `enterActive`. As mentioned in the previous section, this class we'll be added when the element enters. We're also passing the class `animate __animated animate__ lightSpeedOutLeft` for the state `exitActive`. As mentioned in the previous section, this class we'll be added when the element exits. Also we're passing the `timeout` prop with value `900`.

Inside `CSSTransition` we pass the element we want to animate which is an `li` element. The element shows the name of the language and has a `CloseButton` component which on click should remove the language from the list. Please note that the `CloseButton` comes from the [React Bootstrap](https://react-bootstrap.github.io) which we're using just for styling purposes.

As you can see `TransitionGroup` is only used as a wrapper to these elements.

We also need to add a button to add languages:

```
<Button onClick={addLanguage}>Add</Button>
```

What's left is to implement the event listeners `addLanguage` and `removeLanguage`:

```
function addLanguage() {
    const newLanguages = languages.splice(0);
    const newItem = Object.assign({}, randomItems(defaultLanguages, 1)[0]);
    newItem.id = counter;
    newLanguages.push(newItem);
    setLanguages(newLanguages);
    setCounter(counter + 1);
}

function removeLanguage (id) {
    const newLanguages = languages.splice(0);
    const ind = newLanguages.findIndex((language) => language.id === id);
    if (ind !== -1) {
        newLanguages.splice(ind, 1);
        setLanguages(newLanguages);
    }
}
```

The `addLanguage` listener picks a random item from the array. We use `Object.assign` to clone the item from the array instead of getting the item by reference. We then change the `id` to make sure it's unique.

In the `removeLanguage` listener we just find the index of the language in the array and remove it.

That's all! If you try it out, items that are added by clicking on the "Add" button will be animated as they enter. Items will also be animated when they exit by clicking on the X icon.

## Applying Animation With a Switch

The last case we'll cover is animating something based on its change of state. Let's say we have a button that would toggle between two states, and these two states would require a change in the appearance of another element. For this case, we can use the `SwitchTransition` component.

The `SwitchTransition` wraps a `CSSTransition` or `Transition` element. It accepts one prop `mode` which can be of two values: `out-in` or `in-out`, with `out-in` being the default. When choosing `out-in`, it means that the old state exits first then the new state enters. When choosing `in-out` it's the opposite; the new state enters then the old state exits.

When the state of the component changes, the component exits and a new component with the new state enters.

In this example, we'll have an [Alert](https://react-bootstrap.github.io/components/alerts), which is a component exposed by React Bootstrap. We'll have a state that will toggle the `variant`, which is the background color and the theme of the Alert component, between `danger` and `success`. We'll also change the text of the Alert component based on the variant.

First, we'll define the state variable to toggle the state of the Alert component:

```
const [isDanger, setIsDanger] = useState(true);
```

Then, we'll render the `SwitchTransition` component which will take as a child a `CSSTransition` component to manage the animation of the `Alert` component:

```
<SwitchTransition mode="out-in">
    <CSSTransition key={isDanger} classNames={{
		enterActive: 'animate __animated animate__ flipInX',
		exitActive: 'animate __animated animate__ flipOutX'
 	}}
	timeout={500}>
		<Alert variant={isDanger ? 'danger' : 'success'}>{isDanger ? "You're in danger" : "Danger cleared"}</Alert>
	</CSSTransition>
</SwitchTransition>
```

As you can see we pass to `SwitchTransition` the mode `out-in`, but this is the default mode so it's optional to pass.

For `CSSTransition` we pass it the prop `key` which will be used to enter and exit elements based on the state. When the state variable `isDanger` changes, the component will be removed and a new one with the new value will be added. This `key` prop behaves exactly as it would when you render items from an array using `map`.

For the `enterActive` animation state, we add the class `animate __animated animate__ flipInX`. For the `exitActive` animation sate, we add the class `animate __animated animate__ flipOutX`.

As for the child of `CSSTransition` we pass the `Alert` component, which sets the `variant` and text based on the value of `isDanger`.

Finally, we'll render a button to toggle the value of `isDanger`:

```
<Button onClick={() => setIsDanger(!isDanger)}>
	{isDanger ? 'Clear Danger' : 'Bring Danger'}
</Button>
```

If you try it now, you'll see that when you click the button the Alert will exit and the new one will enter. This is because of the mode `out-in`.

If you try to change the mode to `in-out`, you'll see that when you click the button a new Alert will enter and then the old one will exit.

## Conclusion

Adding animation to components provides a nice user experience and add a flair to your website.

In this tutorial, we learned how to use React Transition Group to animate a component's enterance or exit. Remember, this library does not add the animation for you. This library exposes components that will allow you to add the animation yourself.