Skip to content

ReactJS - Animations

Animations can significantly enhance user experience by making UI transitions smoother and more intuitive. React itself doesn’t have a built-in animation system, but it provides hooks for, and integrates well with, third-party animation libraries. One popular choice for managing CSS transitions and animations is react-transition-group.

This chapter will demonstrate how to create basic animations using react-transition-group.

react-transition-group is a library that exposes components for managing the stages of transitions, making it easier to implement animations when components enter or leave the DOM.

Install it using npm or yarn:

your-project-directory> npm install react-transition-group
your-project-directory> yarn add react-transition-group

Animations with react-transition-group rely on CSS transitions or animations. Create a CSS file (e.g., animations.css in your src folder) and import it into your component or main application file.

Example: src/animations.css (we’ll populate this later)

And import it in App.js or main.js:

import './animations.css'; // Adjust path as necessary

The CSSTransition component from react-transition-group helps animate a single component when it first mounts or when its in prop changes.

Let’s create a component that fades in on appear.

import React, { useState, useEffect } from 'react';
import { CSSTransition } from 'react-transition-group';
import './animations.css'; // Make sure to create and import this CSS file
function App() {
const [showTitle, setShowTitle] = useState(false);
// Trigger the animation after the component mounts
useEffect(() => {
setShowTitle(true);
}, []);
return (
<div>
<CSSTransition
in={showTitle} // Controls the transition (true to enter, false to exit)
timeout={500} // Duration of the transition in milliseconds
classNames="fade" // Prefix for CSS classes (e.g., fade-enter, fade-enter-active)
appear // Enable appear transition on initial mount
unmountOnExit // Optional: remove the component from DOM when exited
>
<h1>My Animated Element</h1>
</CSSTransition>
</div>
);
}
export default App;
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.jsx';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
/* Fade Appear Animation */
.fade-appear {
opacity: 0;
}
.fade-appear-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
/* If you also want enter/exit animations for dynamic show/hide later */
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity 500ms ease-in;
}
.fade-exit {
opacity: 1;
}
.fade-exit-active {
opacity: 0;
transition: opacity 500ms ease-in;
}

Explanation:

  • We use useState and useEffect to set showTitle to true after the component mounts, triggering the in prop of CSSTransition.

  • CSSTransition props:

    • in: Boolean. When true, it applies enter/appear classes. When false, it applies exit classes.
    • timeout: Duration of the animation. It should match your CSS transition duration.
    • classNames: A string prefix. react-transition-group will append suffixes like -appear, -appear-active, -enter, -enter-active, -exit, -exit-active.
    • appear: Enables the initial mount animation using *-appear and *-appear-active classes.
    • unmountOnExit: If true, the component will be removed from the DOM after it finishes exiting.

When the app loads, the <h1> element will fade in.

Step 4 - Enter and Leave Animations (TransitionGroup)

Section titled “Step 4 - Enter and Leave Animations (TransitionGroup)”

To animate a list of items (e.g., when adding or removing them), use the TransitionGroup component in conjunction with CSSTransition.

import React, { useState } from 'react';
import { CSSTransition, TransitionGroup } from 'react-transition-group';
import './animations.css'; // Ensure this CSS file includes .item-* classes
import { v4 as uuidv4 } from 'uuid'; // For unique keys: npm install uuid
function App() {
const [items, setItems] = useState([
{ id: uuidv4(), text: 'Item 1...' },
{ id: uuidv4(), text: 'Item 2...' },
]);
const handleAddItem = () => {
const newItemText = prompt('Enter new item text:');
if (newItemText) {
setItems(prevItems => [
...prevItems,
{ id: uuidv4(), text: newItemText },
]);
}
};
const handleRemoveItem = (idToRemove) => {
setItems(prevItems => prevItems.filter(item => item.id !== idToRemove));
};
return (
<div>
<button onClick={handleAddItem}>Add Item</button>
<TransitionGroup component="ul"> {/* component prop defines the wrapping element */}
{items.map(({ id, text }) => (
<CSSTransition
key={id} // Crucial: unique key for each item
timeout={500}
classNames="item"
>
<li onClick={() => handleRemoveItem(id)}>
{text}
</li>
</CSSTransition>
))}
</TransitionGroup>
</div>
);
}
export default App;

src/animations.css (additions for List Animation)

Section titled “src/animations.css (additions for List Animation)”
/* ... (keep .fade-* classes from above if needed) ... */
/* Item Enter/Exit Animation */
.item-enter {
opacity: 0;
transform: translateX(-100px);
}
.item-enter-active {
opacity: 1;
transform: translateX(0);
transition: opacity 500ms ease-in, transform 500ms ease-in;
}
.item-exit {
opacity: 1;
transform: translateX(0);
}
.item-exit-active {
opacity: 0;
transform: translateX(100px);
transition: opacity 500ms ease-in, transform 500ms ease-in;
}

Explanation for List Animation:

  • We use uuid to generate unique IDs for list items, which is essential for TransitionGroup to track items correctly. Install it via npm install uuid.

  • TransitionGroup: Wraps multiple CSSTransition components. It monitors its children. When a child is added or removed, TransitionGroup manages its animation state.

  • CSSTransition (inside map): Each list item is wrapped in its own CSSTransition.

    • The key prop MUST be unique and stable for each item.
    • classNames is set to "item", so CSS classes like item-enter, item-enter-active, etc., will be applied.
  • handleAdd and handleRemove: These functions update the items state. React re-renders, and TransitionGroup detects changes in its children, triggering animations.

When you add an item, it will animate in (slide from left and fade in). When you click an item to remove it, it will animate out (slide to right and fade out).

Note on prompt(): Using prompt() is simple for demos but generally not recommended for production UIs due to its blocking nature and browser-inconsistent styling. In real apps, you’d use a proper input field within your React component.

Further Exploration:

react-transition-group also offers Transition and SwitchTransition components for more granular control. For more complex physics-based animations or interactions, libraries like Framer Motion (https://www.framer.com/motion/) or React Spring (https://www.react-spring.dev/) are excellent choices. Always refer to the official documentation of these libraries for the most up-to-date information and advanced features.