Build a sliding drawer with React and TypeScript

Learn how to build a sliding drawer component with React, TypeScript, and CSS.
May 14, 2023React
4 min read

Sliding drawers are a useful component in any React application. Let's look at how to build a sliding drawer with React, TypeScript, and CSS. We'll make it a clean and lightweight presentation component, without any state or business logic within it. We'll also make it flexible enough to open from either side of the screen.

The drawer component

Let's start off by creating a Drawer.tsx file for the Drawer component. We'll define a few props for the component. An isOpen prop will be used to set the open/closed state of the drawer. A children prop will allow us to pass any content or elements that we want into the drawer. A direction prop will control whether the drawer opens from the left or right of the screen. Lastly, an onClose prop will notify us when the drawer has been closed.

For the sake of simplicity, we'll use an X character as the icon to close the drawer. The className of the outer div element will be comprised of a static .Drawer class, an .Open class when the drawer is open, and a dynamically generated class that is based on the direction.

Drawer.tsx
import * as React from 'react';

import styles from './Drawer.module.css';

enum DrawerDirection {
  Left = 'Left',
  Right = 'Right',
}

type Props = {
  isOpen: boolean;
  children: React.ReactNode;
  direction?: DrawerDirection;
  onClose: () => void;
};

const Drawer = ({
  isOpen,
  children,
  direction = DrawerDirection.Right,
  onClose,
}: Props) => {
  const classNames = `${styles.Drawer} ${styles[direction]} ${
    isOpen ? styles.Open : ''
  }`;

  return (
    <div className={classNames}>
      <div className={styles.Close} onClick={onClose}>
        X
      </div>
      <div className={styles.Content}>{children}</div>
    </div>
  );
};

export { Drawer, DrawerDirection };

Using the drawer component

Let's use the Drawer component in an App component. We included no state in the Drawer component to keep it as a dump/presentation component, without any state logic. Therefore, we will need to define the state for our drawer in the App component.

To do so, we'll create an isDrawerOpen state via useState. We'll pass isDrawerOpen to the isOpen prop of Drawer. Then, we'll use the state setter function, setIsDrawerOpen, when onClose is triggered by the Drawer. Lastly, we'll introduce a button that will be used to open the drawer. When the button is clicked, setIsDrawerOpen will be called to set isDrawerOpen to true.

App.tsx
import * as React from 'react';
import { Drawer } from './components/Drawer';

export default function App() {
  const [isDrawerOpen, setIsDrawerOpen] = React.useState(false);

  return (
    <div>
      <button onClick={() => setIsDrawerOpen(true)}>Open Drawer</button>

      <Drawer isOpen={isDrawerOpen} onClose={() => setIsDrawerOpen(false)}>
        <p>Drawer</p>
      </Drawer>
    </div>
  );
}

Styling the drawer component

When defining the CSS rules for the .Drawer class, we set a z-index with a value above the other elements on the page. This is so that the sliding drawer opens on top of what's on the page. The drawer's height is set to take up the full height of the page. The width can be customized based on our needs. We could also introduce a width prop for the Drawer to support multiple drawer widths. Lastly, we used a transition rule to animate the left and right transforms that are applied by the respective classes.

The .Left and .Right classes hide the drawer from view by applying a 100% translation along the x-axis. Then, the .Open class, when applied, will bring the drawer into view by resetting the translation to 0%.

Drawer.module.css
.Drawer {
  position: fixed;
  z-index: 2;
  top: 0;
  width: 90%;
  height: 100%;
  background: #eee;
  transition: transform 0.5s ease-out;
}

.Drawer.Left {
  left: 0;
  transform: translateX(-100%);
  box-shadow: -0.5rem 0 1.5rem #000;
}

.Drawer.Left .Close {
  position: absolute;
  top: 1rem;
  right: 1rem;
  display: flex;
  cursor: pointer;
}

.Drawer.Right {
  right: 0;
  transform: translateX(100%);
  box-shadow: 0.5rem 0 1.5rem #000;
}

.Drawer.Right .Close {
  position: absolute;
  top: 1rem;
  left: 1rem;
  display: flex;
  cursor: pointer;
}

.Drawer .Content {
  margin: 4rem 1rem 1rem;
}

.Drawer.Open {
  transform: translateX(0%);
}

Drawer demo

Here's a demo of the sliding drawer that we just created in this blog post.

Conclusion

We just built a lightweight, flexible, and reusable sliding drawer with React, TypeScript, and CSS! Feel free to use it for your next React project.

New
Be React Ready

Learn modern React with TypeScript.

Learn modern React development with TypeScript from my books React Ready and React Router Ready.