Build Your Own react‑transition‑group: From Zero to Custom Transition Components

This article walks through the inner workings of react‑transition‑group by manually implementing Transition, CSSTransition, SwitchTransition and TransitionGroup components, explaining their lifecycle states, callback hooks, and how to orchestrate enter/exit animations with concise TypeScript/JavaScript examples.

ELab Team
ELab Team
ELab Team
Build Your Own react‑transition‑group: From Zero to Custom Transition Components

Preface

When using React to mount and unmount a component the process happens instantly, making it difficult to add enter and exit animations. react‑transition‑group solves this by exposing the mounting and unmounting phases and allowing custom actions at each stage.

Overview

react‑transition‑group provides four core components:

Transition

CSSTransition

SwitchTransition

TransitionGroup

The article demonstrates how to implement a minimal version of each component to understand their underlying mechanics.

Implementing a Transition from Scratch

Manual Transition Example

1.1 Example

import { Transition } from 'react-transition-group';
function Demo() {
  const [inProp, setInProp] = useState(false);
  return (
    <div>
      <Transition in={inProp} timeout={2000}>
        {state => <h1>{state}</h1>}
      </Transition>
      <button onClick={() => setInProp(!inProp)}>Click to Enter</button>
    </div>
  );
}
When the button is first clicked (inProp changes from false to true) the displayed text goes through “entering → entered”. Clicking again (true to false) produces “entered → exiting → exited”.

1.2 Core Principle

Transition receives in and timeout props. It manages five states: entering, entered, exiting, exited, and unmounted. The child can be a function that receives the current state, enabling different UI for each phase.

1.3 Manual Implementation

Define a TypeScript interface with callbacks ( onEnter, onEntering, onEntered, onExit, onExiting, onExited) and timeout.

Implement a class component that stores status in state, updates it in lifecycle methods, and provides helper methods such as performEnter, performExit, safeSetState, onTransitionEnd, and updateStatus.

The implementation shows how to transition between states, schedule callbacks, and cancel pending callbacks to avoid race conditions.

This simple version does not handle the initial mounting phases or component removal after exit.

Manual CSSTransition

2.1 Example

import React, { useState } from 'react';
import CSSTransition from 'react-transition-group';
export default function CSSTransitionDemo() {
  const [inProp, setInProp] = useState(false);
  return (
    <>
      <CSSTransition in={inProp} timeout={2000} classNames="my-node">
        <div id="test">I'll receive my-node-* classes</div>
      </CSSTransition>
      <button type="button" onClick={() => setInProp(!inProp)}>Click to Enter</button>
    </>
  );
}
First click adds classes “my-node-enter”, “my-node-enter-active”, then after 2 s “my-node-enter-done”. Second click adds “my-node-exit”, “my-node-exit-active”, then “my-node-exit-done”.

2.2 Core Principle

CSSTransition forwards the same lifecycle callbacks as Transition and automatically adds CSS class names for each phase (base, active, done) based on the classNames prop.

2.3 Manual Implementation

Wrap Transition and compute class names for each status.

Inject class names at the appropriate callbacks ( onEnter, onEntering, onEntered, onExit, onExiting, onExited).

The code demonstrates how to add and remove class names, force a repaint when necessary, and delegate to user‑provided callbacks.

Manual SwitchTransition

3.1 Core Principle

SwitchTransition supports two modes:

out‑in : the new component waits until the old component finishes its exit animation before entering.

in‑out : the new component enters immediately while the old component exits.

It tracks the key of its child to detect a switch and renders a combination of entering and exiting components according to the selected mode.

3.2 Manual Implementation

Helper functions clone children with appropriate in values and callbacks. Two rendering maps ( enterRenders and leaveRenders) return the correct JSX for each mode and status. The component maintains status, current, and a flag indicating whether it has been mounted to control the first‑render animation.

Manual TransitionGroup

4.1 Example

import React from 'react';
import { CSSTransition, TransitionGroup } from '@/pages/react-transition-group/min-react-transition-group';
import './index.less';
export default class TodoList extends React.Component {
  state = { items: ['hello', 'world', 'click', 'me'] };
  count = 1;
  handleAdd() {
    const newItems = this.state.items.concat([`item-${this.count++}`]);
    this.setState({ items: newItems });
  }
  handleRemove(i) {
    const newItems = this.state.items.slice();
    newItems.splice(i, 1);
    this.setState({ items: newItems });
  }
  render() {
    return (
      <div>
        <button onClick={() => this.handleAdd()}>Add Item</button>
        <TransitionGroup>
          {this.state.items.map((item, i) => (
            <CSSTransition key={item} timeout={2000} classNames="friend">
              <div>{item}<button onClick={() => this.handleRemove(i)}>remove</button></div>
            </CSSTransition>
          ))}
        </TransitionGroup>
      </div>
    );
  }
}

The accompanying CSS defines .friend-enter, .friend-enter-active, .friend-exit, and .friend-exit-active to animate items sliding in from the right and out to the left.

4.2 Core Principle

TransitionGroup stores the previous children mapping, compares it with the next mapping, and:

For newly added items, clones them with in=true to trigger an enter animation.

For removed items, clones them with in=false to trigger an exit animation and removes them after the onExited callback fires.

This logic ensures that list updates are animated smoothly.

Conclusion

react‑transition‑group does not provide animations itself; it supplies a Transition component that manages the mounting and unmounting lifecycle. CSSTransition adds CSS‑based styling, SwitchTransition enables animated component switches, and TransitionGroup coordinates animations for a collection of elements.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ELab Team
Written by

ELab Team

Sharing fresh technical insights

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.