<div id="app"></div>
body {
  font-family: Helvetica, Arial, sans-serif;
  background: #ECF0F1;
  color: #555;
}

.Wrapper {
  padding: 30px;
  max-width: 800px;
  overflow-x: hidden;
  margin: 0 auto;
  position: relative;
}

.Dummy {
  padding: 25px;
}

p {
  line-height: 1.4em;
  margin-bottom: 10px;
  
  &:last-child {
    margin-bottom: 0;
  }
}

.TransitionHeight {
  border: 1px solid #DDD;
  border-radius: 5px;
  background: #fff;
}

.Button {
  margin: 0 0 15px;
  border: 1px solid #ddd;
  background: #fff;
  font-size: 16px;
  border-radius: 50px;
  padding: 10px 18px;
  transition: all 300ms;
  outline: none;

  &:hover {
    color: #2980B9;
    border-color: lighten(#2980B9, 30);
    cursor: pointer;
  }
}
View Compiled
const ANIMATION_DURATION = 1000;

class TransitionHeight extends React.Component {
  constructor() {
    super();
    
    this.state = {
      previousChildren: null,
      height: 'auto',
      previousChildrenOpacity: 0,
      childrenOpacity: 1,
      animate: false,
    };
  }
  
  componentWillReceiveProps(nextProps) {
    const {
      children,
    } = this.props;
    
    if (children !== nextProps.children) {
      // Set animation initial state
      this.setState({
        previousChildren: children,
        height: this.mainElement.offsetHeight,
        previousChildrenOpacity: 1,
        childrenOpacity: 0,
      });
      
      cancelAnimationFrame(this.animationStartRequestID);
      // 50ms delay to let react render init state
      this.animationStartRequestID = requestAnimationFrame(() => {
        // Set animation end state
        this.setState({
          previousChildrenOpacity: 0,
          childrenOpacity: 1,
          height: this.contentElement.offsetHeight,
          animate: true,
        });
        
        clearTimeout(this.animationEndTimeoutID);
        // When animation is finished, reset state
        this.animationEndTimeoutID = setTimeout(() => {
          this.setState({
            previousChildren: null,
            height: 'auto',
            animate: false,
          });
        }, ANIMATION_DURATION);
      });
    }
  }
  
  render() {
    const {
      children,
    } = this.props;
    const {
      previousChildren,
      height,
      previousChildrenOpacity,
      childrenOpacity,
      animate,
    } = this.state;
    
    const mainElementStyle = {
      position: 'relative',
      transition: animate ? `all ${ ANIMATION_DURATION }ms` : null,
      height,
      overflow: 'hidden',
    };
        
    const childrenStyle = {
      transition: animate ? `all ${ ANIMATION_DURATION }ms` : null,
      opacity: childrenOpacity,
    };
        
    const previousChildrenStyle = {
      position: 'absolute',
      width: '100%',
      transition: animate ? `all ${ ANIMATION_DURATION }ms` : null,
      top: 0,
      left: 0,
      opacity: previousChildrenOpacity,
    };
    
    return (
      <div
        style={ mainElementStyle }
        ref={ el => this.mainElement = el }
        className='TransitionHeight'
      >
        <div
          style={ childrenStyle }
          ref={ el => this.contentElement = el }
        >
          { children }
        </div>
        <div style={ previousChildrenStyle }>
          { previousChildren }
        </div>
      </div>
    );
  }
}

class App extends React.Component {
  constructor() {
    super();
    
    this.state = {
      swap: false,
    };
  }
  
  render() {
    return (
      <div className='Wrapper'>
        <button 
          className='Button' 
          onClick={ () => this.setState({ swap: !this.state.swap }) }
        >
          Swap
        </button>
        <TransitionHeight>
          { this.state.swap ?
            <div className='Dummy'>
              <p>Short one</p>
              <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                Integer efficitur, augue in euismod pretium, erat metus bibendum nisi,
                at dictum lorem sapien vitae risus. Etiam et aliquam nisl.
                Donec placerat nibh ut tellus elementum, quis pulvinar orci dictum.
                Quisque convallis nisl in eros consequat, ut aliquam ante suscipit.
                Sed pharetra eros maximus suscipit viverra. Fusce posuere lorem in neque porttitor,
                eget dignissim erat pharetra. Proin fermentum orci purus.
                Nam ultricies sodales imperdiet. Mauris at nibh quis ex fermentum blandit.
                Integer sit amet sagittis sapien.
              </p>
            </div> :
            <div className='Dummy'>
              <p>Longer one</p>
              <p>
                Donec placerat nibh ut tellus elementum, quis pulvinar orci dictum.
                Quisque convallis nisl in eros consequat, ut aliquam ante suscipit.
                Sed pharetra eros maximus suscipit viverra. Fusce posuere lorem in neque porttitor,
                eget dignissim erat pharetra. Proin fermentum orci purus.
                Nam ultricies sodales imperdiet. Mauris at nibh quis ex fermentum blandit.
                Integer sit amet sagittis sapien.
              </p>
              <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                Integer efficitur, augue in euismod pretium, erat metus bibendum nisi,
                at dictum lorem sapien vitae risus. Etiam et aliquam nisl.
                Donec placerat nibh ut tellus elementum, quis pulvinar orci dictum.
                Quisque convallis nisl in eros consequat, ut aliquam ante suscipit.
                Sed pharetra eros maximus suscipit viverra. Fusce posuere lorem in neque porttitor,
                eget dignissim erat pharetra. Proin fermentum orci purus.
                Nam ultricies sodales imperdiet. Mauris at nibh quis ex fermentum blandit.
                Integer sit amet sagittis sapien.
              </p>
              <p>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                Integer efficitur, augue in euismod pretium, erat metus bibendum nisi,
                at dictum lorem sapien vitae risus. Etiam et aliquam nisl.
                Donec placerat nibh ut tellus elementum, quis pulvinar orci dictum.
                Quisque convallis nisl in eros consequat, ut aliquam ante suscipit.
                Sed pharetra eros maximus suscipit viverra. Fusce posuere lorem in neque porttitor,
                eget dignissim erat pharetra. Proin fermentum orci purus.
                Nam ultricies sodales imperdiet. Mauris at nibh quis ex fermentum blandit.
                Integer sit amet sagittis sapien.
              </p>
            </div> }
        </TransitionHeight>
      </div>
    )
  }
}
  
  
ReactDOM.render(<App />, document.getElementById('app'));
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react/15.6.1/react-dom.js