We use cookies to enhance your experience on the site
CodeWorlds

CSS Animations and Keyframes in React

Spaceships do not suddenly appear on the radar screen - they fly in, pulse a signal, and smoothly move along their orbit. Animations in web interfaces work on the same principle: they add dynamics to the application and help the user understand what is happening. In this lesson, you will learn techniques for creating CSS animations in React applications - from simple transitions to complex keyframe sequences, and finally we will look at the React Transition Group library.

CSS @keyframes with styled-components

The

@keyframes
rule allows you to define a sequence of animation steps. In styled-components, we use the
keyframes
helper, which generates a unique animation name and prevents conflicts:

1import styled, { keyframes } from 'styled-components';
2
3// Animation definition - radar signal pulsing
4const radarPulse = keyframes`
5  0% {
6    transform: scale(1);
7    opacity: 1;
8  }
9  50% {
10    transform: scale(1.5);
11    opacity: 0.5;
12  }
13  100% {
14    transform: scale(2);
15    opacity: 0;
16  }
17`;
18
19const RadarDot = styled.div`
20  width: 20px;
21  height: 20px;
22  border-radius: 50%;
23  background: #00ff88;
24  animation: ${radarPulse} 2s ease-out infinite;
25`;

Key elements:

  • keyframes
    is imported from
    styled-components
    (not from CSS)
  • Inside we define percentage steps (
    0%
    ,
    50%
    ,
    100%
    ) or keywords (
    from
    ,
    to
    )
  • We use interpolation
    ${radarPulse}
    in the
    animation
    property

You can define any number of keyframes and combine them in different components:

1const floatInSpace = keyframes`
2  0%, 100% { transform: translateY(0px); }
3  50% { transform: translateY(-15px); }
4`;
5
6const rotateOrbit = keyframes`
7  from { transform: rotate(0deg); }
8  to { transform: rotate(360deg); }
9`;
10
11const SpaceStation = styled.div`
12  animation: ${floatInSpace} 4s ease-in-out infinite;
13`;
14
15const OrbitRing = styled.div`
16  animation: ${rotateOrbit} 10s linear infinite;
17`;

Transition - Smooth State Changes

The

transition
property in CSS is the simplest way to animate value changes. Instead of defining keyframes, you tell the browser: "when this property changes, do it smoothly." This is the ideal solution for hover effects, clicks, or component state changes.

1const NavButton = styled.button`
2  background: #1a1a3e;
3  color: #00ff88;
4  padding: 12px 24px;
5  border: 2px solid #00ff88;
6  border-radius: 8px;
7  cursor: pointer;
8
9  /* Define what should be animated and how */
10  transition: all 0.3s ease;
11
12  &:hover {
13    background: #00ff88;
14    color: #1a1a3e;
15    transform: scale(1.05);
16    box-shadow: 0 0 20px rgba(0, 255, 136, 0.4);
17  }
18`;

transition
syntax:

1transition: property duration timing-function delay;
  • property
    - what we animate (
    all
    ,
    background
    ,
    transform
    ,
    opacity
    ...)
  • duration
    - how long the transition lasts (
    0.3s
    ,
    200ms
    )
  • timing-function
    - animation curve (
    ease
    ,
    linear
    ,
    ease-in-out
    ,
    cubic-bezier()
    )
  • delay
    - start delay (optional)

You can animate multiple properties with different parameters:

1const ShipPanel = styled.div`
2  opacity: 0.8;
3  transform: translateX(0);
4  background: #0a0a2e;
5
6  transition:
7    opacity 0.2s ease,
8    transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94),
9    background 0.3s ease;
10
11  &:hover {
12    opacity: 1;
13    transform: translateX(10px);
14    background: #1a1a4e;
15  }
16`;

Animation - Continuous Animations

The

animation
property is a more advanced version of
transition
. It allows for continuous, repeating animations, reverse playback, and control over every aspect of movement:

1const warningBlink = keyframes`
2  0%, 100% { opacity: 1; }
3  50% { opacity: 0.3; }
4`;
5
6const WarningLight = styled.div`
7  width: 16px;
8  height: 16px;
9  border-radius: 50%;
10  background: #ff4444;
11
12  animation-name: ${warningBlink};
13  animation-duration: 1s;
14  animation-timing-function: ease-in-out;
15  animation-iteration-count: infinite;
16  animation-direction: alternate;
17`;

Or in shorthand form:

1animation: name duration timing-function delay iteration-count direction fill-mode;

Key parameters:

  • iteration-count
    -
    infinite
    (endless) or number of repetitions (
    3
    )
  • direction
    -
    normal
    ,
    reverse
    ,
    alternate
    (back and forth)
  • fill-mode
    -
    forwards
    (keep final state),
    backwards
    ,
    both
  • play-state
    -
    running
    or
    paused
    (playback control)

Dynamic Animations Based on Props

In styled-components, you can create animations that respond to component props. This allows dynamically adjusting movement to the application state:

1const moveShip = keyframes`
2  from { transform: translateX(0); }
3  to { transform: translateX(100%); }
4`;
5
6const Spaceship = styled.div`
7  width: 60px;
8  height: 30px;
9  background: #4488ff;
10  clip-path: polygon(0% 50%, 30% 0%, 100% 50%, 30% 100%);
11
12  animation: ${moveShip} ${props => props.speed || 3}s linear infinite;
13  animation-play-state: ${props => props.isFlying ? 'running' : 'paused'};
14  opacity: ${props => props.isFlying ? 1 : 0.5};
15  transition: opacity 0.3s ease;
16`;
17
18function FlightControl() {
19  const [isFlying, setIsFlying] = useState(false);
20  const [speed, setSpeed] = useState(3);
21
22  return (
23    <div>
24      <Spaceship isFlying={isFlying} speed={speed} />
25
26      <button onClick={() => setIsFlying(!isFlying)}>
27        {isFlying ? 'Stop' : 'Fly'}
28      </button>
29
30      <input
31        type="range"
32        min="0.5"
33        max="5"
34        step="0.5"
35        value={speed}
36        onChange={(e) => setSpeed(e.target.value)}
37      />
38      <span>Speed: {speed}s per orbit</span>
39    </div>
40  );
41}

You can also dynamically select different keyframes depending on state:

1const slideIn = keyframes`
2  from { transform: translateX(-100%); opacity: 0; }
3  to { transform: translateX(0); opacity: 1; }
4`;
5
6const slideOut = keyframes`
7  from { transform: translateX(0); opacity: 1; }
8  to { transform: translateX(100%); opacity: 0; }
9`;
10
11const Panel = styled.div`
12  animation: ${props => props.isVisible ? slideIn : slideOut} 0.4s ease forwards;
13`;

This approach allows animating element entry and exit - the panel slides in from the left when appearing and slides out to the right when disappearing.

React Transition Group - CSSTransition

Native CSS cannot animate elements that are added to or removed from the DOM (e.g., through conditional rendering

{show && <Component />}
). The React Transition Group library solves this problem by managing the enter/exit animation lifecycle.

The most commonly used component is

CSSTransition
:

1import { CSSTransition } from 'react-transition-group';
2import { useState, useRef } from 'react';
3
4function NotificationPanel() {
5  const [showAlert, setShowAlert] = useState(false);
6  const nodeRef = useRef(null);
7
8  return (
9    <div>
10      <button onClick={() => setShowAlert(!showAlert)}>
11        {showAlert ? 'Hide alert' : 'Show alert'}
12      </button>
13
14      <CSSTransition
15        in={showAlert}
16        timeout={300}
17        classNames="alert"
18        unmountOnExit
19        nodeRef={nodeRef}
20      >
21        <div ref={nodeRef} className="alert-box">
22          Object detected on radar!
23        </div>
24      </CSSTransition>
25    </div>
26  );
27}

CSSTransition
automatically adds and removes CSS classes at the appropriate moments:

1/* Entry - start */
2.alert-enter {
3  opacity: 0;
4  transform: translateY(-20px);
5}
6
7/* Entry - active phase */
8.alert-enter-active {
9  opacity: 1;
10  transform: translateY(0);
11  transition: opacity 300ms ease, transform 300ms ease;
12}
13
14/* Exit - start */
15.alert-exit {
16  opacity: 1;
17  transform: translateY(0);
18}
19
20/* Exit - active phase */
21.alert-exit-active {
22  opacity: 0;
23  transform: translateY(-20px);
24  transition: opacity 300ms ease, transform 300ms ease;
25}

Key

CSSTransition
props:

  • in
    - boolean controlling whether the element is visible
  • timeout
    - animation duration (in ms), should match the CSS transition
  • classNames
    - CSS class prefix (e.g.,
    "alert"
    generates
    alert-enter
    ,
    alert-enter-active
    , etc.)
  • unmountOnExit
    - removes the element from DOM after exit animation
  • nodeRef
    - ref to the animated element (recommended to avoid warnings)

Transition vs Animation - When to Use Which?

Let's summarize when to use each technique:

transition
- for simple state changes:

  • Hover, focus, active effects
  • Color, size, position changes on interaction
  • Simple entries/exits (opacity, transform)

@keyframes
+
animation
- for complex and continuous animations:

  • Pulsing, rotating, floating
  • Multi-step animations (more than 2 states)
  • Infinite background or decoration animations

React Transition Group - for component lifecycle animations:

  • Animated mounting/unmounting of elements
  • Lists with animated adding/removing of elements
  • Transitions between views/pages

Well-designed animations are like a ship's navigation system - they guide the user, provide feedback, and make the interface feel natural, like flying through the galaxy with a warp drive, not teleporting without warning.

Go to CodeWorlds