Drawer

A panel that slides in from a screen edge. It is an HTML popover: a DrawerToggle button opens and closes it through popovertarget, and the browser closes it on Escape or a click outside and shows it...

A panel that slides in from a screen edge. It is an HTML popover: a DrawerToggle button opens and closes it through popovertarget, and the browser closes it on Escape or a click outside and shows it in the top layer, above everything. None of that needs JavaScript, so a drawer works on a prerendered page with scripts off - the mobile navigation menu, for example.

With JavaScript, it can also be controlled from state (isOpen / onClose), and while open it moves focus inside, keeps Tab cycling within it, locks body scroll, and returns focus when it closes. The surface is a Paper pinned to the chosen edge, with a slide-in that respects prefers-reduced-motion; the page behind is dimmed through the popover's ::backdrop.

Usage

import { Drawer, DrawerToggle } from '@soroush.tech/design-system/Drawer'

<DrawerToggle drawer="nav" aria-label="Open navigation">
  <Icon name="menu" />
</DrawerToggle>

<Drawer id="nav" anchor="left">
  <Navigation />
  <DrawerToggle drawer="nav" action="hide">Close</DrawerToggle>
</Drawer>

Controlled, with JavaScript:

const [isOpen, setIsOpen] = useState(false)

<Drawer id="filters" anchor="right" isOpen={isOpen} onClose={() => setIsOpen(false)}>
  <Filters />
</Drawer>

The drawer's content is always in the page (hidden while closed), so it is server-rendered and indexable; left / right drawers fill the window's height, top / bottom its width.

Examples

Default

Drawer

Slides in from the "left" edge. Press Escape or click outside to close.

const args: Partial<DrawerProps> = {
  anchor: 'left',
  elevation: 16,
  hasBackdrop: true,
  transitionDuration: 225,
  id: 'drawer',
}

<>
  <DrawerToggle drawer="drawer">Open drawer</DrawerToggle>
  <Drawer {...args} id="drawer">
    <DrawerBody args={args} />
  </Drawer>
</>

Controlled

Drawer

Slides in from the "right" edge. Press Escape or click outside to close.

const args: Partial<DrawerProps> = { anchor: 'right', elevation: 16, hasBackdrop: true, transitionDuration: 225 }

<ControlledDemo {...args} />