A react component toolset for managing animations
—
The ReplaceTransition component is a specialized transition component that animates between exactly two children. It provides a controlled way to switch between two specific components with proper transition timing.
Animates between two children based on the in prop value, using TransitionGroup internally for coordination.
/**
* Specialized transition component that animates between exactly two children
* @param props - ReplaceTransition props
* @returns JSX element managing two-child transitions
*/
function ReplaceTransition({
in: inProp,
children,
onEnter,
onEntering,
onEntered,
onExit,
onExiting,
onExited,
...otherProps
}): JSX.Element;
interface ReplaceTransitionProps {
/** Controls which child is shown (true = first child, false = second child) */
in: boolean;
/** Must be exactly two transition components (Transition or CSSTransition) */
children: [React.ReactElement, React.ReactElement];
/** Callback fired before the "entering" status is applied */
onEnter?: (node?: HTMLElement) => void;
/** Callback fired after the "entering" status is applied */
onEntering?: (node?: HTMLElement) => void;
/** Callback fired after the "entered" status is applied */
onEntered?: (node?: HTMLElement) => void;
/** Callback fired before the "exiting" status is applied */
onExit?: (node?: HTMLElement) => void;
/** Callback fired after the "exiting" status is applied */
onExiting?: (node?: HTMLElement) => void;
/** Callback fired after the "exited" status is applied */
onExited?: (node?: HTMLElement) => void;
}Usage Examples:
import React, { useState } from 'react';
import { ReplaceTransition, CSSTransition } from 'react-transition-group';
import './replace.css';
function ReplaceExample() {
const [showFirst, setShowFirst] = useState(true);
return (
<div>
<ReplaceTransition in={showFirst}>
<CSSTransition
timeout={300}
classNames="fade"
key="first"
>
<div className="content first">
First Content
</div>
</CSSTransition>
<CSSTransition
timeout={300}
classNames="fade"
key="second"
>
<div className="content second">
Second Content
</div>
</CSSTransition>
</ReplaceTransition>
<button onClick={() => setShowFirst(!showFirst)}>
Switch Content
</button>
</div>
);
}
// Image slider with replace transitions
function ImageSlider() {
const [currentIndex, setCurrentIndex] = useState(0);
const images = [
{ src: 'image1.jpg', alt: 'First image' },
{ src: 'image2.jpg', alt: 'Second image' }
];
return (
<div className="slider">
<ReplaceTransition in={currentIndex === 0}>
<CSSTransition
timeout={500}
classNames="slide"
key="image1"
>
<img
src={images[0].src}
alt={images[0].alt}
className="slider-image"
/>
</CSSTransition>
<CSSTransition
timeout={500}
classNames="slide"
key="image2"
>
<img
src={images[1].src}
alt={images[1].alt}
className="slider-image"
/>
</CSSTransition>
</ReplaceTransition>
<button
onClick={() => setCurrentIndex(currentIndex === 0 ? 1 : 0)}
>
Next Image
</button>
</div>
);
}ReplaceTransition automatically:
in={true}, second child when in={false}ReplaceTransition requires exactly two children:
// ✅ Correct - exactly two children
<ReplaceTransition in={showFirst}>
<CSSTransition timeout={200} classNames="fade" key="first">
<div>First</div>
</CSSTransition>
<CSSTransition timeout={200} classNames="fade" key="second">
<div>Second</div>
</CSSTransition>
</ReplaceTransition>
// ❌ Incorrect - wrong number of children
<ReplaceTransition in={showFirst}>
<CSSTransition timeout={200} classNames="fade">
<div>Only one child</div>
</CSSTransition>
</ReplaceTransition>ReplaceTransition maps its lifecycle callbacks to the child components in a specific way:
When transitioning to first child (in={true}):
onEnter, onEntering, onEntered map to first child's corresponding callbacksWhen transitioning to second child (in={false}):
onEnter, onEntering, onEntered map to second child's onEnter, onEntering, onEntered callbacksfunction CallbackExample() {
const [active, setActive] = useState(true);
return (
<ReplaceTransition
in={active}
onEnter={() => console.log('Child entering')}
onExit={() => console.log('Child exiting')}
>
<CSSTransition
timeout={200}
classNames="first"
key="first"
onEntered={() => console.log('First child entered')}
>
<div>First</div>
</CSSTransition>
<CSSTransition
timeout={200}
classNames="second"
key="second"
onEntered={() => console.log('Second child entered')}
>
<div>Second</div>
</CSSTransition>
</ReplaceTransition>
);
}/* Fade transition */
.fade-enter {
opacity: 0;
}
.fade-enter-active {
opacity: 1;
transition: opacity 300ms ease-in-out;
}
.fade-exit {
opacity: 1;
}
.fade-exit-active {
opacity: 0;
transition: opacity 300ms ease-in-out;
}
/* Slide transition for image replacement */
.slide-enter {
transform: translateX(100%);
}
.slide-enter-active {
transform: translateX(0);
transition: transform 500ms ease-out;
}
.slide-exit {
transform: translateX(0);
}
.slide-exit-active {
transform: translateX(-100%);
transition: transform 500ms ease-in;
}
/* Cross-fade transition */
.crossfade-enter {
opacity: 0;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.crossfade-enter-active {
opacity: 1;
transition: opacity 400ms ease-in-out;
}
.crossfade-exit {
opacity: 1;
position: absolute;
top: 0;
left: 0;
right: 0;
}
.crossfade-exit-active {
opacity: 0;
transition: opacity 400ms ease-in-out;
}ReplaceTransition is ideal for:
For more complex switching scenarios with multiple options, consider using SwitchTransition instead.
Install with Tessl CLI
npx tessl i tessl/npm-react-transition-group