Drawer

A modal side sheet that slides in from an edge. Same behaviour and parts as Dialog, with side and size props on Content.

Import

tsx
import { Drawer } from "@merid/react";

Anatomy

tsx
<Drawer.Root>
  <Drawer.Trigger />
  <Drawer.Content side="right">
    <Drawer.Title />
    <Drawer.Description />
    <Drawer.Footer />
  </Drawer.Content>
</Drawer.Root>

Root, Trigger, Title, Description, Close and Footer are the Dialog parts. The Footer is pushed to the bottom of the sheet.

Examples

Sides

Sizes

size sets the sheet width: sm 320px, md 420px (default), lg 560px, always capped to the viewport minus 48px.

Controlled

tsx
const [open, setOpen] = useState(false);

<Drawer.Root open={open} onOpenChange={setOpen}>
  <Drawer.Content>…</Drawer.Content>
</Drawer.Root>

API reference

Drawer.Root

PropTypeDefaultDescription
openboolean–Controlled open state.
defaultOpenbooleanfalseInitial open state when uncontrolled.
onOpenChange(open: boolean) => void–Called when the open state should change.
childrenReactNode–Trigger, Content and anything else sharing this drawer's state.

Drawer.Content

Accepts every <div> attribute except role.

PropTypeDefaultDescription
side"left" | "right""right"Edge the sheet slides in from.
sizeDrawerSize"md"Sheet width: `sm` 320px, `md` 420px, `lg` 560px, capped to the viewport minus 48px. `DrawerSize` is `"sm" | "md" | "lg"`.
closeOnOutsidePressbooleantrueClose when the backdrop is pressed.
closeOnEscapebooleantrueClose on Escape.
initialFocusRefObject<HTMLElement | null>–Element to focus when opened; defaults to [data-autofocus], then the first tabbable element.
containerElement | nulldocument.bodyPortal target. `undefined` uses `document.body`; `null` renders nothing until the target exists.
showClosebooleantrueRender the standard top-right icon close button automatically. Skipped while you render your own icon `Close`.
closeLabelstring"Close"Accessible name of the automatic close button.
refRef<HTMLDivElement>–Forwarded ref to the drawer element.

Trigger, Title, Description, Close and Footer take the same props as in Dialog.

Styling

ClassElement
.mrd-drawer__backdropFixed backdrop; aligns the sheet to its side
.mrd-drawerThe sheet: 320 / 420 / 560px by data-size, capped at 100vw - 48px, full height

Both carry data-side="left" | "right" and data-state="open"; the sheet also carries data-size. Title, description, footer and close use the .mrd-dialog__* classes. Motion is removed under prefers-reduced-motion.

Accessibility

Follows the WAI-ARIA Dialog (Modal) pattern: role="dialog", aria-modal="true", focus trap, scroll lock and focus return.

KeyAction
SpaceEnterOn the trigger, opens the drawer.
TabMoves focus forward, wrapping inside the drawer.
ShiftTabMoves focus backwards, wrapping inside the drawer.
EscCloses the drawer and returns focus to the trigger.

Guidelines

Do

Use a drawer for secondary content that benefits from keeping the page in view: filters, details, settings.

Avoid

Put a multi-step flow in a drawer; use a page.