React / React Transitions / react-transition-group
Home /React /React Transitions /react-transition-group

react-transition-group

react-transition-group

react-transition-group solves the hardest problem in React UI transitions: animating components as they mount and unmount. It exposes four components, each solving a different patterns.

terminal
INSTALL

npm install react-transition-group

1 <Transition>: Lifecycle States

The base component. Exposes four states: entering, entered, exiting, exited. You write the CSS or JS logic yourself.

FadeTransition.js

import { Transition } from 'react-transition-group';

const duration = 300;

const defaultStyle = {
  transition: `opacity ${duration}ms ease`,
  opacity: 0,
};

const transitionStyles = {
  entering: { opacity: 1 },
  entered:  { opacity: 1 },
  exiting:  { opacity: 0 },
  exited:   { opacity: 0 },
};

export function FadeTransition({ in: inProp, children }) {
  return (
    <Transition
      in={inProp}
      timeout={duration}
      unmountOnExit       {/* removes from DOM after exit */}
    >
      {state => (
        <div style={{ ...defaultStyle, ...transitionStyles[state] }}>
          {children}
        </div>
      )}
    </Transition>
  );
}

2 <CSSTransition>: Class-Based (Most Common)

The most frequently used component. Automatically adds/removes CSS class names at each lifecycle stage. You just write the CSS.

Modal.jsx
JSX

import { CSSTransition } from 'react-transition-group';
import './Modal.css';

export function Modal({ isOpen, onClose, children }) {
  return (
    <CSSTransition
      in={isOpen}
      timeout={350}
      classNames="modal"   {/* prefix for CSS classes */}
      unmountOnExit
    >
      <div className="modal-overlay" onClick={onClose}>
        <div
          className="modal-content"
          onClick={e => e.stopPropagation()}
        >
          {children}
        </div>
      </div>
    </CSSTransition>
  );
}

Modal.css
CSS

/* CSSTransition automatically adds these classes: */
/* .modal-enter, .modal-enter-active, .modal-enter-done */
/* .modal-exit,  .modal-exit-active,  .modal-exit-done  */

.modal-enter .modal-content       { opacity: 0; transform: scale(0.9) translateY(-20px); }
.modal-enter-active .modal-content {
  opacity: 1;
  transform: scale(1) translateY(0);
  transition: all 350ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.modal-exit .modal-content        { opacity: 1; transform: scale(1); }
.modal-exit-active .modal-content  {
  opacity: 0;
  transform: scale(0.9);
  transition: all 300ms ease;
}

.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,0.5);
  display: grid;
  place-items: center;
}

3 <SwitchTransition>: Mode-Controlled Swap

For swapping between two components (e.g. route changes, tab switches). Supports out-in (exit first, then enter) and in-out modes.

TabSwitcher.jsx
JSX

import { SwitchTransition, CSSTransition } from 'react-transition-group';

export function TabSwitcher({ activeTab }) {
  return (
    <SwitchTransition mode="out-in">
      <CSSTransition
        key={activeTab}         {/* key change triggers transition */}
        timeout={200}
        classNames="tab"
      >
        <div className="tab-content">
          {renderTab(activeTab)}
        </div>
      </CSSTransition>
    </SwitchTransition>
  );
}

4 <TransitionGroup>: List Animations

Wraps a list of CSSTransition components and manages adding/removing items with transitions automatically.

AnimatedList.jsx
JSX

import { TransitionGroup, CSSTransition } from 'react-transition-group';

export function AnimatedList({ items }) {
  return (
    <TransitionGroup component="ul">
      {items.map(item => (
        <CSSTransition
          key={item.id}
          timeout={400}
          classNames="list-item"
        >
          <li>{item.text}</li>
        </CSSTransition>
      ))}
    </TransitionGroup>
  );
}

/* CSS */
/*
.list-item-enter             { opacity: 0; transform: translateX(-20px); }
.list-item-enter-active      { opacity: 1; transform: translateX(0); transition: all 400ms ease; }
.list-item-exit              { opacity: 1; transform: translateX(0); }
.list-item-exit-active       { opacity: 0; transform: translateX(20px); transition: all 300ms ease; }
*/