Drawer

A side panel that opens on the start edge of the screen, for menus and filters.

Use Drawer for content that opens over the page from the side, such as a mobile menu or a filter panel. For a centred dialog, use Modal.

Example

app/components/layout/MobileMenu.tsx
import { useState } from 'react';
import { Drawer } from '@salla.sa/twilight-theme-engine/drawer';
import { Link } from '@salla.sa/twilight-theme-engine/common';

export function MobileMenu() {
  const [open, setOpen] = useState(false);
  return (
    <>
      <button onClick={() => setOpen(true)} aria-label="Menu">Menu</button>
      <Drawer isOpen={open} onClose={() => setOpen(false)}>
        <Drawer.Header onClose={() => setOpen(false)}>Menu</Drawer.Header>
        <Drawer.Body>
          <Link to="/products" onClick={() => setOpen(false)}>Products</Link>
        </Drawer.Body>
      </Drawer>
    </>
  );
}

You own the open state: the drawer only asks you to close it through onClose.

API

PropTypeDescription
isOpenbooleanWhether the drawer is shown. Required.
onClose() => voidCalled on Escape or backdrop click. Required.
childrenReactNodeDrawer content. Required.
size?"sm" | "md" | "lg" | "full"Width: w-64, w-80, w-96 or full width. Default: "md".
closeOnBackdropClick?booleanClose when the backdrop is clicked. Default: true.
closeOnEscape?booleanClose on the Escape key. Default: true.
preventBodyScroll?booleanLock page scroll while open. Default: true.
className?stringClass on the drawer panel.

Parts: Drawer.Header, Drawer.Body and Drawer.Footer. Each accepts normal div attributes. Drawer.Header also takes showCloseButton (default true) and onClose.

Gotchas

  • There is no position prop. The drawer opens on the left in left-to-right themes and on the right when the theme is RTL.
  • The close button in Drawer.Header appears only when you pass onClose to the header too.
  • It renders nothing while closed and during server rendering, so it never appears in the server HTML.
  • While open it adds the class menu-opened to <body>, and on close focus returns to the element that had it before.
  • It reads the theme direction, so it must be inside TwilightProvider (your root route already is).

Next

On this page