Build a sliding drawer with React and TypeScript
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
.
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
.
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 {
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.