React provides a ReactTransitionGroup
addon component as a low-level API for animation, and a ReactCSSTransitionGroup
for easily implementing basic CSS animations and transitions.
ReactCSSTransitionGroup
#ReactCSSTransitionGroup
is based on ReactTransitionGroup
and is an easy way to perform CSS transitions and animations when a React component enters or leaves the DOM. It's inspired by the excellent ng-animate library.
ReactCSSTransitionGroup
is the interface to ReactTransitions
. This is a simple element that wraps all of the components you are interested in animating. Here's an example where we fade list items in and out.
/** @jsx React.DOM */
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var TodoList = React.createClass({
getInitialState: function() {
return {items: ['hello', 'world', 'click', 'me']};
},
handleAdd: function() {
var newItems =
this.state.items.concat([prompt('Enter some text')]);
this.setState({items: newItems});
},
handleRemove: function(i) {
var newItems = this.state.items;
newItems.splice(i, 1);
this.setState({items: newItems});
},
render: function() {
var items = this.state.items.map(function(item, i) {
return (
<div key={item} onClick={this.handleRemove.bind(this, i)}>
{item}
</div>
);
}.bind(this));
return (
<div>
<button onClick={this.handleAdd}>Add Item</button>
<ReactCSSTransitionGroup transitionName="example">
{items}
</ReactCSSTransitionGroup>
</div>
);
}
});
In this component, when a new item is added to ReactCSSTransitionGroup
it will get the example-enter
CSS class and the example-enter-active
CSS class added in the next tick. This is a convention based on the transitionName
prop.
You can use these classes to trigger a CSS animation or transition. For example, try adding this CSS and adding a new list item:
.example-enter {
opacity: 0.01;
transition: opacity .5s ease-in;
}
.example-enter.example-enter-active {
opacity: 1;
}
You'll notice that when you try to remove an item ReactCSSTransitionGroup
keeps it in the DOM. If you're using an unminified build of React with add-ons you'll see a warning that React was expecting an animation or transition to occur. That's because ReactCSSTransitionGroup
keeps your DOM elements on the page until the animation completes. Try adding this CSS:
.example-leave {
opacity: 1;
transition: opacity .5s ease-in;
}
.example-leave.example-leave-active {
opacity: 0.01;
}
In order for it to apply transitions to its children, the ReactCSSTransitionGroup
must already be mounted in the DOM. The example below would not work, because the ReactCSSTransitionGroup
is being mounted along with the new item, instead of the new item being mounted within it. Compare this to the Getting Started section above to see the difference.
render: function() {
var items = this.state.items.map(function(item, i) {
return (
<div key={item} onClick={this.handleRemove.bind(this, i)}>
<ReactCSSTransitionGroup transitionName="example">
{item}
</ReactCSSTransitionGroup>
</div>
);
}, this);
return (
<div>
<button onClick={this.handleAdd}>Add Item</button>
{items}
</div>
);
}
Although in the example above we rendered a list of items into ReactCSSTransitionGroup
, the children of ReactCSSTransitionGroup
can be one or zero items. This makes it possible to animate a single element entering or leaving. Similarly, you can animate a new element replacing the current element, with the new element animating in while the current animates out. For example, we can implement a simple image carousel like this:
/** @jsx React.DOM */
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
var ImageCarousel = React.createClass({
propTypes: {
imageSrc: React.PropTypes.string.isRequired
},
render: function() {
return (
<div>
<ReactCSSTransitionGroup transitionName="carousel">
<img src={this.props.imageSrc} key={this.props.imageSrc} />
</ReactCSSTransitionGroup>
</div>
);
}
});
Note:
You must provide the
key
attribute for all children ofReactCSSTransitionGroup
, even if rendering a single item. This is how React will determine which children have entered, left, or stayed.
You can disable animating enter
or leave
animations if you want. For example, sometimes you may want an enter
animation and no leave
animation, but ReactCSSTransitionGroup
waits for an animation to complete before removing your DOM node. You can add transitionEnter={false}
or transitionLeave={false}
props to ReactCSSTransitionGroup
to disable these animations.
Note:
When using
ReactCSSTransitionGroup
, there's no way for your components to be notified when a transition has ended or to perform any more complex logic around animation. If you want more fine-grained control, you can use the lower-levelReactTransitionGroup
API which provides the hooks you need to do custom transitions.
ReactTransitionGroup
#ReactTransitionGroup
is the basis for animations. When children are declaratively added or removed from it (as in the example above) special lifecycle hooks are called on them.
componentWillEnter(callback)
#This is called at the same time as componentDidMount()
for components added to an existing TransitionGroup
. It will block other animations from occurring until callback
is called. It will not be called on the initial render of a TransitionGroup
.
componentDidEnter()
#This is called after the callback
function that was passed to componentWillEnter
is called.
componentWillLeave(callback)
#This is called when the child has been removed from the ReactTransitionGroup
. Though the child has been removed, ReactTransitionGroup
will keep it in the DOM until callback
is called.
componentDidLeave()
#This is called when the willLeave
callback
is called (at the same time as componentWillUnmount
).
By default ReactTransitionGroup
renders as a span
. You can change this behavior by providing a component
prop. For example, here's how you would render a <ul>
:
<ReactTransitionGroup component={React.DOM.ul}>
...
</ReactTransitionGroup>
Every DOM component is under React.DOM
. However, component
does not need to be a DOM component. It can be any React component you want; even ones you've written yourself!