CSSTransition to make a slide out drawer in css grid layout

1.7k Views Asked by At

I am trying to make a slide out drawer utilizing the npm package react-transition-group. For whatever reason, I cannot seem to get the drawer to slide out from left to right on clicking the additional criteria button. If you can solve this issue without using the package, that is ok too!

Here is the code I am trying to get to work as a React component:

{/* DeveloperSearch.js */}
      <CSSTransition
        in={sidebarClicked}
        appear
        timeout={1000}
        classNames="drawer"
        mountOnEnter
        unmountOnExit
      >
        <div className="DevSearch__additional-search-criteria">
          Additional Search Criteria
          <div className="DevSearch__additional-search-criteria-individual">
            <div
              style={{
                fontSize: '0.8rem',
                marginBottom: '5px',
                fontWeight: 'bold',
              }}
            >
              Only show people who match more than {criteriaMatch}% of all
              search criteria
            </div>
            <input
              className="form-control"
              type="number"
              value={criteriaMatch}
              onChange={(e) => setCriteriaMatch(e.target.value)}
              min={0}
              max={100}
              step={5}
            />
          </div>
        </div>
      </CSSTransition>

I also have a css file that is specifically for the CSS Transition component called DeveloperSearch.css:

.drawer-exit {
  width: 250px;
}

.drawer-exit.drawer-exit-active {
  width: 250px;
  transition: width 1000ms ease-in;
}

.drawer-exit-done {
  width: 0px;
}

.drawer-enter {
  width: 250px;
}

.drawer-enter.drawer-enter-active {
  width: 250px;
  transition: all 1000ms ease-in;
}

Unfortunately, my results are no where near what I was wanting, as the drawer does not seem to slide out at all...

Issue # 1

I also have replicated this issue in a codesandbox that can be found by clicking here. Thanks for your help!

3

There are 3 best solutions below

2
sathya reddy On

Here is a pure css based solution but this is a bit hacky

  1. Markup
const Drawer = ({ transitionExit, handleExit }) => (
  <div
    onClick={handleExit}
    className={`drawer ${transitionExit ? "exit" : ""}`}
  >
    <p>Home</p>
    <p>About</p>
    <p>Contact</p>
    <p>Close Drawer</p>
  </div>
);

export default function App() {
  const [isOpen, setIsOpen] = useState(false);
  const [transitionExit, setTransitionExit] = useState(false);

  const handleExit = () => {
    setTransitionExit(true);
    setTimeout(() => {
      setIsOpen(false);
      setTransitionExit(false);
      // timeout should be less than animation time otherwise state might still be true
      // after animation ends and drawer appears for few milliseconds
    }, 450);
  };

  return (
    <div className="App">
      <div className="wrapper">
        <div className="sidebar_container">
          <button onClick={() => setIsOpen(true)}>open</button>
        </div>
        {isOpen && (
          <div className={`container ${transitionExit ? "exit" : ""}`}>
            <Drawer handleExit={handleExit} transitionExit={transitionExit} />
          </div>
        )}
      </div>
    </div>
  );
}
  1. CSS
.wrapper {
  height: 90vh;
  max-width: 60vw;
  display: grid;
  grid-template-columns: 30% 70%;
  overflow: hidden;
  margin: 40px;
}

.sidebar_container {
  width: 100px;
  height: 100%;
  background-color: rgb(250, 207, 213);
  padding: 30px;
  position: relative;
  z-index: 30;
}

@keyframes containerTransitionEnter {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
@keyframes drawerTransitionEnter {
  0% {
    opacity: 0;
    left: -10vw;
  }
  100% {
    opacity: 1;
    left: 0vw;
  }
}

@keyframes containerTransitionExit {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
@keyframes drawerTransitionExit {
  0% {
    opacity: 1;
    left: 0vw;
  }
  100% {
    opacity: 0;
    left: -10vw;
  }
}

.container {
  position: relative;
  z-index: 10;
  height: 90vh;
  animation: containerTransitionEnter 0.5s;
}
.drawer {
  box-sizing: border-box;
  position: relative;
  height: 90vh;
  width: 25vw;
  padding: 20px;
  background-color: rgb(4, 118, 156);
  border-right: 1px solid rgba(0, 0, 0, 0.3);
  animation: drawerTransitionEnter 0.5s;
}
p {
  margin-bottom: 10px;
  color: white;
}

.container.exit {
  animation: containerTransitionExit 0.5s;
}

.drawer.exit {
  animation: drawerTransitionExit 0.5s;
}

Here is the link to codesandbox

0
Shivam Suchak On

Since you are using react you can use Material UI for this Here

and you can try this in your case

<Drawer
            className={classes.drawer}
            variant=''
            anchor='left'
            open={open}
            classes={{
                paper: classes.drawerPaper,
            }}>
            <div className={classes.drawerHeader}>
                <IconButton onClick={handleDrawerClose}>
                    {theme.direction === 'ltr' ? (
                        <ChevronLeftIcon />
                    ) : (
                        <ChevronRightIcon />
                    )}
                </IconButton>
            </div>
            <Divider />
            <List>
                {arr.map((text, index) => (
                    <ListItem
                        button
                        key={text}
                        onClick={
                            text === 'Home'
                                ? goToHome
                                : text === 'About'
                                ? handleOpenAbout
                                : text === 'Contact'
                                ? goToContact
                                : text == 'Team'
                                ? goToMyTea,
                                : goToDashboard
                        }>
                        <ListItemIcon>
                            {text === 'Home' ? (
                                <HomeIcon />
                            ) : text === 'About' ? (
                                <NoteAddIcon />
                            ) : text === 'About' || text === 'Contact' ? (
                                <ListAltIcon />
                            ) : text === 'Dashboard' ? (
                                <DashboardIcon />
                            ) : (
                                <></>
                            )}
                        </ListItemIcon>
                        <ListItemText primary={text} />
                    </ListItem>
                ))}
            </List>
        </Drawer>
0
Hossein Azizdokht On

You should not delete div that has class="DevSearch__additional-search-criteria drawer-enter-done" from the DOM. In this case, Transition will not work. If you want to delete it, you must use css animation. In this way, after adding div to the DOM, put animation on it to enter as a slider