A React component to animate replacing one element with another.
npm install react-css-transition-replaceA React component to animate replacing one element with another.
While ReactCSSTransitionGroup does a great job
of animating changes to a list of components and can even be used to animate the replacement of one item
with another, proper handling of the container height in the latter case is not built in. This component
is designed to do exactly that with an API closely following that of ReactCSSTransitionGroup.
Using react-css-transition-replace provides two distinct benefits:
- It automatically handles the positioning of the animated components, and
- _allows changes in the height of container to be handled and animated with ease when
various content heights differ, even when absolute positioning is used._
Animations are fully configurable with CSS, including having the entering component wait to enter until
the leaving component's animation completes. Following suit with the
React.js API the one caveat is
that the transition duration must be specified in JavaScript as well as CSS.
Live Examples |
Change Log |
Upgrade Guide
Install via npm:
```
npm install --save react-css-transition-replace
All functional child components must be wrapped in forwardRef to work correctly.
A ReactCSSTransitionReplace component can only have a single child. Other than that, the basic usageReactCSSTransitionGroup
follows the exact same API as , with support for transitionEnter, transitionLeavetransitionAppear
and . When the key of the child component changes, the previous component is animated out
and the new component animated in. During this process:
- All leaving components continue to be rendered; if the animation is slow there may be multiple components
in the process of leaving.
- The entering component is positioned on top of the leaving component(s) with absolute positioning.transitionName
- The height of the container is set to that of the leaving component, and then immediately to that of the
entering component. If the is a String the {animation-name}-height class name is appliedtransitionName
to it, and if is an Object the transitionName.height class will be used if present.isLeaving
- The leaving component will be passed an prop while transitioning out.
This provides many possibilities for animating the replacement as illustrated in the examples below.
Additionally, the boolean property changeWidth can be used to animate changing the width of the component.
This change will happen at the same time as changing the height. Animating this change should be done using
the same class name that is used for animating the change in height.
It is also possible to remove the child component (i.e. leave ReactCSSTransitionReplace with no children)height
which will animate the going to zero along with the leave transition. Similarly, a single childReactCSSTransitionReplace
can be added to an empty , triggering the inverse animation.
By default a span is rendered as a wrapper of the child components. Each child is also wrapped in a spancomponent
used in the positioning of the actual rendered child. These can be overridden with the andchildComponent props respectively.
The ReactCSSTransitionReplace component is used exactly like its ReactCSSTransitionGroup counterpart:
`javascript
import ReactCSSTransitionReplace from 'react-css-transition-replace';
render() {
return (
);
}
`
To realize cross-fading of two components all that remains is to define the enter and leave opacity
transitions in the associated CSS classes:
`css
.cross-fade-leave {
opacity: 1;
}
.cross-fade-leave.cross-fade-leave-active {
opacity: 0;
transition: opacity 1s ease-in;
}
.cross-fade-enter {
opacity: 0;
}
.cross-fade-enter.cross-fade-enter-active {
opacity: 1;
transition: opacity 1s ease-in;
}
.cross-fade-height {
transition: height 0.5s ease-in-out;
}
`
Note the additional .cross-fade-height class. This indicates how the container height is to be
animated if the heights of the entering and leaving components are not the same. You can see this
in action here.
To fade a component out and wait for its transition to complete before fading in the next, simply
add a delay to the enter transition.
`css
.fade-wait-leave {
opacity: 1;
}
.fade-wait-leave.fade-wait-leave-active {
opacity: 0;
transition: opacity 0.4s ease-in;
}
.fade-wait-enter {
opacity: 0;
}
.fade-wait-enter.fade-wait-enter-active {
opacity: 1;
/ Delay the enter animation until the leave completes /
transition: opacity 0.4s ease-in 0.6s;
}
.fade-wait-height {
transition: height 0.6s ease-in-out;
}
`
_Note:_ The transitionEnterTimeout specified in the JS must be long enough to allow for the delay and
the duration of the transition. In this case:
`javascript`
See the live example here.
Animated transitions of react-router v4 routes is supported with two caveats shown in the example below:
1. The current location must be applied to the Switch to force it to maintain the previous matched route onSwitch
the leaving component.
2. If the might render null, i.e. there is no catch-all "*" route, the Switch must be wrapped in adiv
or similar for the leave transition to work; if not the previous component will disappear instantaneously
when there is no match.
`javascript`
Home
One
Two
Three (no match)
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
>
)}
/>
See the live example here.
For smoother transitions hardware acceleration, which is achieved by using translate3d instead of the 2D
translations, should be used whenever possible. For example, to realize a mobile app transition between
pages one might use:
`css
.page-enter,
.page-leave {
position: absolute;
-webkit-transition: transform 250ms ease-in-out, opacity 250ms ease-in-out;
transition: transform 250ms ease-in-out, opacity 250ms ease-in-out;
}
.page-enter {
left: 100vw;
}
.page-enter.page-enter-active {
-webkit-transform: translate3d(-100vw, 0, 0);
transform: translate3d(-100vw, 0, 0);
}
.page-leave {
left: 0;
}
.page-leave.page-leave-active {
-webkit-transform: translate3d(-100vw, 0, 0);
transform: translate3d(-100vw, 0, 0);
}
`
`javascript`
transitionEnterTimeout={250}
transitionLeaveTimeout={250}
>
My page 01 content
1. In general animating block or inline-block level elements is more stable that inline elements. If thespan
height changes in random ways ensure that there isn't a or other inline element used as the outeroverflow
element of the components being animated.
2. The of the container is set to 'hidden' automatically, which changes the behaviour of'visible'
collapsing margins from the default
. This may cause a glitch in the height at the start or end of animations. To avoid this you can:overflowHidden={false}
- Keep the overflow hidden permanently with custom styles/classes if that will not cause undesired side-effects.
- Only use
Single-direction margin declarations
to avoid collapsing margins overall.
- Turn this feature off by setting the prop when hidden overflow is not needed,.*-height
for example when transitions are in place and content is of the same height.
3. If the class (or transitionName.height`) is not specified the change in container height will not
be animated but instead jump to the height of the entering component instantaneously. It can, therefore, be
omitted if all content is known to be of the same height without any adverse side-effects, and absolute positioning
related height issues will still be avoided.
PRs are welcome.
This software is free to use under the MIT license.
See the LICENSE file for license text and copyright information.