CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-transition-group

A react component toolset for managing animations

Pending
Overview
Eval results
Files

transition-group.mddocs/

Transition Groups

The TransitionGroup component manages a set of transition components in a list, automatically coordinating the mounting and unmounting of items with proper transition timing.

Capabilities

TransitionGroup Component

Manages transitions for dynamic lists of components, handling enter and exit animations for list items.

/**
 * Manages a set of transition components in a list with automatic coordination
 * @param props - TransitionGroup props
 * @returns JSX element containing managed transition children
 */
function TransitionGroup({
  component,
  children,
  appear,
  enter,
  exit,
  childFactory,
  ...otherProps
}): JSX.Element;

interface TransitionGroupProps {
  /** Component to render as container (default: 'div', use null for no wrapper) */
  component?: React.ComponentType<any> | string | null;
  /** Set of Transition or CSSTransition components to manage */
  children?: React.ReactNode;
  /** Enable/disable appear animations for all children */
  appear?: boolean;
  /** Enable/disable enter animations for all children */
  enter?: boolean;
  /** Enable/disable exit animations for all children */
  exit?: boolean;
  /** Function to wrap every child, including exiting ones */
  childFactory?: (child: React.ReactElement) => React.ReactElement;
}

Usage Examples:

import React, { useState } from 'react';
import { TransitionGroup, CSSTransition } from 'react-transition-group';
import './list.css';

function TodoList() {
  const [items, setItems] = useState([
    { id: 1, text: 'Buy milk' },
    { id: 2, text: 'Walk dog' },
    { id: 3, text: 'Write code' }
  ]);

  const addItem = () => {
    const newItem = {
      id: Date.now(),
      text: `Item ${items.length + 1}`
    };
    setItems([...items, newItem]);
  };

  const removeItem = (id) => {
    setItems(items.filter(item => item.id !== id));
  };

  return (
    <div>
      <TransitionGroup component="ul" className="todo-list">
        {items.map(item => (
          <CSSTransition
            key={item.id}
            timeout={300}
            classNames="item"
          >
            <li onClick={() => removeItem(item.id)}>
              {item.text}
            </li>
          </CSSTransition>
        ))}
      </TransitionGroup>
      <button onClick={addItem}>Add Item</button>
    </div>
  );
}

// Without wrapper element
function NoWrapperGroup({ items }) {
  return (
    <TransitionGroup component={null}>
      {items.map(item => (
        <CSSTransition
          key={item.id}
          timeout={200}
          classNames="fade"
        >
          <div className="item">{item.text}</div>
        </CSSTransition>
      ))}
    </TransitionGroup>
  );
}

Child Factory Function

The childFactory prop allows modification of children, including those that are exiting:

/**
 * Child factory function for modifying transition children
 * @param child - React element being managed by TransitionGroup
 * @returns Modified React element
 */
type ChildFactory = (child: React.ReactElement) => React.ReactElement;

Usage Example:

function DynamicTransitionGroup({ items, fastExit }) {
  const childFactory = (child) => {
    // Modify exiting children to use faster animation
    return React.cloneElement(child, {
      timeout: fastExit ? 100 : 300,
      classNames: fastExit ? 'fast-exit' : 'normal'
    });
  };

  return (
    <TransitionGroup childFactory={childFactory}>
      {items.map(item => (
        <CSSTransition
          key={item.id}
          timeout={300}
          classNames="normal"
        >
          <div>{item.text}</div>
        </CSSTransition>
      ))}
    </TransitionGroup>
  );
}

List Animation Patterns

Common patterns for animating lists with TransitionGroup:

Staggered Animations:

function StaggeredList({ items }) {
  return (
    <TransitionGroup component="div" className="staggered-list">
      {items.map((item, index) => (
        <CSSTransition
          key={item.id}
          timeout={300}
          classNames="stagger"
          style={{ animationDelay: `${index * 50}ms` }}
        >
          <div className="list-item">
            {item.text}
          </div>
        </CSSTransition>
      ))}
    </TransitionGroup>
  );
}

Complex List Operations:

function AdvancedList() {
  const [items, setItems] = useState([]);

  const handleReorder = (fromIndex, toIndex) => {
    const newItems = [...items];
    const [removed] = newItems.splice(fromIndex, 1);
    newItems.splice(toIndex, 0, removed);
    setItems(newItems);
  };

  return (
    <TransitionGroup component="div">
      {items.map(item => (
        <CSSTransition
          key={item.id}
          timeout={{ enter: 300, exit: 200 }}
          classNames="list-item"
        >
          <div 
            className="draggable-item"
            onDragEnd={(e) => handleReorder(...)}
          >
            {item.text}
          </div>
        </CSSTransition>
      ))}
    </TransitionGroup>
  );
}

TransitionGroup Behavior

TransitionGroup automatically:

  1. Tracks children by key: Uses React keys to identify which items are entering, staying, or leaving
  2. Manages transition props: Automatically sets in prop to true for entering items and false for exiting items
  3. Handles exit cleanup: Removes components from DOM after exit transition completes
  4. Coordinates timing: Ensures proper sequencing of enter/exit animations

Key Requirements

All children of TransitionGroup must have unique key props:

// ✅ Correct - each child has unique key
<TransitionGroup>
  {items.map(item => (
    <CSSTransition key={item.id} timeout={200} classNames="fade">
      <div>{item.text}</div>
    </CSSTransition>
  ))}
</TransitionGroup>

// ❌ Incorrect - missing or duplicate keys will cause issues
<TransitionGroup>
  {items.map(item => (
    <CSSTransition timeout={200} classNames="fade">
      <div>{item.text}</div>
    </CSSTransition>
  ))}
</TransitionGroup>

Example CSS for List Animations

/* Slide in from right, slide out to left */
.item-enter {
  transform: translateX(100%);
  opacity: 0;
}

.item-enter-active {
  transform: translateX(0);
  opacity: 1;
  transition: all 300ms ease-out;
}

.item-exit {
  transform: translateX(0);
  opacity: 1;
}

.item-exit-active {
  transform: translateX(-100%);
  opacity: 0;
  transition: all 200ms ease-in;
}

/* Scale and fade */
.scale-enter {
  transform: scale(0.8);
  opacity: 0;
}

.scale-enter-active {
  transform: scale(1);
  opacity: 1;
  transition: all 250ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.scale-exit {
  transform: scale(1);
  opacity: 1;
}

.scale-exit-active {
  transform: scale(0.8);
  opacity: 0;
  transition: all 150ms ease-in;
}

Install with Tessl CLI

npx tessl i tessl/npm-react-transition-group

docs

css-transition.md

index.md

replace-transition.md

switch-transition.md

transition-group.md

transition.md

tile.json