Animate React Modal

darKnight picture darKnight · Oct 12, 2019 · Viewed 15.6k times · Source

I have a Modal in my web app which I want to slide in when the user clicks "open" button. I am using react-transition-group to achieve this. But I am unable to get the animation working. Not sure what's wrong here?

import React from 'react';
import ReactDOM from 'react-dom';
import { CSSTransition } from 'react-transition-group';
import Modal from 'react-modal';

import './styles.css';

class Example extends React.Component {
  state = {
    isOpen: false,
  };

  toggleModal = () => {
    this.setState(prevState => ({
      isOpen: !prevState.isOpen,
    }));
  };
  render() {
    const modalStyles = {
      overlay: {
        backgroundColor: '#ffffff',
      },
    };
    return (
      <div>
        <button onClick={this.toggleModal}>
          Open Modal
        </button>
        <CSSTransition
          in={this.state.isOpen}
          timeout={300}
          classNames="dialog"
        >
          <Modal
            isOpen={this.state.isOpen}
            style={modalStyles}
          >
            <button onClick={this.toggleModal}>
              Close Modal
            </button>
            <div>Hello World</div>
          </Modal>
        </CSSTransition>
      </div>
    );
  }
}

CSS File:

.dialog-enter {
  left: -100%;
  transition: left 300ms linear;
}
.dialog-enter-active {
  left: 0;
}
.dialog-exit {
  left: 0;
  transition: left 300ms linear;
}
.dialog-exit-active {
  left: -100%;
}

Here is the working code.

Answer

Peter Ambruzs picture Peter Ambruzs · Oct 12, 2019

The problem here is that react-modal uses a react-portal as its mounting point. So it is not rendered as the children of the CSSTransition component. So you could not use the CSSTransition with it.

You can use some custom css to create transition effects. It is in the react-modal documentation.

So if you add this to your css. There will be transition.

.ReactModal__Overlay {
  opacity: 0;
  transform: translateX(-100px);
  transition: all 500ms ease-in-out;
}

.ReactModal__Overlay--after-open {
  opacity: 1;
  transform: translateX(0px);
}

.ReactModal__Overlay--before-close {
  opacity: 0;
  transform: translateX(-100px);
}

And we have to add the closeTimeoutMS prop to the modal in order the closing animation to work.

      <Modal
        closeTimeoutMS={500}
        isOpen={this.state.isOpen}
        style={modalStyles}
      >

https://codesandbox.io/s/csstransition-component-forked-7jiwn