javascripthtmlcssreact-transition-groupreactcsstransitiongroup

Not able to create a smooth scroll with CSSTransition Group


I am trying to use CSSTransitionGroup (or ReactTransitionGroup) to create a vertical smooth scroll effect for content as it appears and disappears from the dom.

I am aware of ways to animate such an effect using transition in pure css, but I need to be able to do this in React when an item appears in and then leaves the DOM, so CSSTransitionGroup seemed like the right solution.

While I am able to animate properties like color and opacity, I am unsuccessful in animating properties like height and/or max-height to achieve the gradual disappearance of the content from top to the bottom or bottom to the top.

How can I animate a smooth scroll effect like this when an item enters and leaves the DOM? My current code using the CSSTransitionGroup is as follows:

class App extends React.Component {
  state = {
    random: true
  };

  toggleItem = () => {
    this.setState({
      random: !this.state.random
    });
  };

  render() {
    console.log("random", this.state.random);
    return (
      <div>
        <button onClick={this.toggleItem}>toggle item</button>
        <br />
        <CSSTransition
          in={this.state.random}
          timeout={400}
          classNames="alert"
          unmountOnExit
          appear
          enter={false}
        >
          <div class="back">
            Hello adsffd asdfadfs asdfasd asdfasdf asdfasfa fdasfas asdfasdf
            afdsafas asdfasd asdfasdf asdfadsf asdfads asdfads asdfasdf
            asdfadsadsf world Hello adsffd asdfadfs asdfasd asdfasdf asdfasfa
            fdasfas asdfasdf afdsafas asdfasd asdfasdf asdfadsf asdfads asdfads
            asdfasdf asdfadsadsf world Hello adsffd asdfadfs asdfasd asdfasdf
            asdfasfa fdasfas asdfasdf afdsafas asdfasd asdfasdf asdfadsf asdfads
            asdfads asdfasdf asdfadsadsf world Hello adsffd asdfadfs asdfasd
            asdfasdf asdfasfa fdasfas asdfasdf afdsafas asdfasd asdfasdf
          </div>
        </CSSTransition>
      </div>
    );
  }
}
export default App;

And the current class I have for enter states is:

.alert-enter {
  height: 0px;
  visibility: hidden;
  overflow: hidden;
}
.alert-enter-active {
  height: auto;
  overflow: auto;

  visibility: visible;
  transition: all 300ms;
}

Solution

  • You can add a white div and transition for it to wrap your text div

    class App extends Component {
    state = {
        random: false
      };
    
      toggleItem = () => {
        this.setState({
          random: !this.state.random
        });
      };
    
      render() {
        return (
          <div>
            <button onClick={this.toggleItem}>toggle item</button>
            <br />
            <div className="back">
              Hello adsffd asdfadfs asdfasd asdfasdf asdfasfa fdasfas asdfasdf
              afdsafas asdfasd asdfasdf asdfadsf asdfads asdfads asdfasdf
              asdfadsadsf world Hello adsffd asdfadfs asdfasd asdfasdf asdfasfa
              fdasfas asdfasdf afdsafas asdfasd asdfasdf asdfadsf asdfads asdfads
              asdfasdf asdfadsadsf world Hello adsffd asdfadfs asdfasd asdfasdf
              asdfasfa fdasfas asdfasdf afdsafas asdfasd asdfasdf asdfadsf asdfads
              asdfads asdfasdf asdfadsadsf world Hello adsffd asdfadfs asdfasd
              asdfasdf asdfasfa fdasfas asdfasdf afdsafas asdfasd asdfasdf
              <CSSTransition
                in={this.state.random}
                timeout={1000}
                classNames="alert"
                unmountOnExit
              >
                <div className="white" />
              </CSSTransition>
            </div>
          </div>
        );
      }
    }
    

    style.css

    .alert-enter {
      transform: translateY(400px);
    }
    .alert-enter-active {
      transform: translateY(0px);
      transition: all 1000ms;
    }
    .alert-exit {
      transform: translateY(0px);
    }
    .alert-exit-active {
      transform: translateY(800px);
      transition: all 3000ms;
    }
    .back {
      position: relative;
      overflow: hidden;
    }
    .white {
      height: 100%;
      position: absolute;
      top: 0;
      left: 0;
      background: white;
      width: 100%;
    }
    

    You can check here CodeSandBox. Hope it helps