javascriptcssreactjstransitionreact-transition-group

CSS Transition from React Transition Group not working and I can't figure out why


I have an app in which I'm trying to have the menu slide out from the left side. I can get it to just appear when the menu button is clicked. However, I'm using CSSTransition from React Transition Group to create the slide effect but it will not work. When I click the menu button, the menu appears immediately (no delay) but when I click the menu button again, the menu disappears after the timeout (500ms delay). There is no transition for either the opening or closing of the menu though. I'm not sure why the delay only happens when closing the menu. I tried to see what happened if I got rid of the "unmountOnExit" under the CSSTransition but that just made the menu appear constantly without any change from the button click.

This is what my code looks like:

import './App.css';

import React, { useState } from 'react';
import { CSSTransition } from 'react-transition-group';

function App() {

   const [open, setOpen] = useState(false);

   function toggleOpen() {
        setOpen(!open);
    }

      return (
          <NavBar toggleOpen={toggleOpen} open={open}></NavBar>
      )
}

function NavBar(props) {

  function DropdownMenu() {
    return (
      <div className="DropdownMenu">
      </div>  
    )
  }

    return (
      <div className="NavBar">
        <div className="Menu-button" onClick={props.toggleOpen}>
          <div></div>
          <div></div>
          <div></div>
        </div>
        <CSSTransition
          in={props.open}
          timeout={500}
          className="Menu-open"
          unmountOnExit>
          <DropdownMenu/>
        </CSSTransition>
      </div>
    )  
}            

export default App;

The CSS code is the following:

.NavBar {
  position: fixed;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  top: 0;
  width: 100%;
  height: 60px;
  background-color: gray;
  border-bottom: solid black 1px;
}

.Menu-button {
  background-color: transparent;
  padding-top: 0.5rem;
  cursor: pointer;
  margin: 20px;
  padding: 0;
}

.Menu-button div {
  width: 35px;
  height: 5px;
  background-color: #fff;
  margin: 6px 0;
  transition: 0.4s;
}

.DropdownMenu {
  position: fixed;
  top: 58px;
  right: 5px;
  width: 34%;
  height: 500px;
  border-radius: 5px;
  background-color: lightgray;
}

.menu-open-enter {
  position: absolute;
  transform: translateX(-110%);
}
.menu-open-enter-active {
  transform: translateX(0%);
  transition: all 500ms ease;
}
.menu-open-exit {
  position: absolute;
}
.menu-open-exit-active {
  transform: translateX(-110%);
  transition: all 500ms ease;
}

Solution

  • There's a couple of issues here:

    Per the react-transition-group docs, the CSSTransition component accepts a classNames prop – not to be confused with the className prop used to pass css styles directly to HTML elements.

    As a separate problem, you're providing the classname Menu-open which react-transition-group would suffix to make Menu-open-enter, Menu-open-exit etc. CSS identifiers are case-sensitive, so this won't match your style declarations of .menu-open-enter, .menu-open-exit ....

    Changing that one line to classNames="menu-open" causes the animation to start working, although it looks a bit weird sliding between the center of the page and the right edge. I suspect you want to use transform: translateX(110%) rather than -110%.

    Sandbox