Components

Drawer

An off-canvas panel anchored to an edge of the viewport over a dimmed scrim: a bordered head with a title and close button, a scrollable body, and an optional footer. Slides in via a transform, anchored right by default — or left, top, bottom.

Static panel

The drawer panel on its own (the fixed .ds-drawer-overlay scrim is omitted here so it renders in flow). Head, scrollable body, and a footer pushing the primary action right with a .ds-drawer__spacer.

Panel

Filters

Body content…

<div class="ds-drawer-overlay is-open">
  <div class="ds-drawer ds-drawer--right" role="dialog" aria-modal="true">
    <div class="ds-drawer__head">
      <h2 class="ds-drawer__title">Filters</h2>
      <button class="ds-button ds-drawer__close">Close</button>
    </div>
    <div class="ds-drawer__body"><p>Body content…</p></div>
    <div class="ds-drawer__foot">
      <button class="ds-button">Clear</button>
      <span class="ds-drawer__spacer"></span>
      <button class="ds-button ds-button--primary">Apply</button>
    </div>
  </div>
</div>

Placement

Modifiers dock the panel to an edge: .ds-drawer--right (default) and .ds-drawer--left for side panels, .ds-drawer--top / .ds-drawer--bottom for sheets.

right · left · top · bottom

Navigation

A left-anchored panel.

<div class="ds-drawer ds-drawer--left">…</div>
<div class="ds-drawer ds-drawer--right">…</div>
<div class="ds-drawer ds-drawer--top">…</div>
<div class="ds-drawer ds-drawer--bottom">…</div>

Interactive

A trigger opens the live fixed overlay; it closes on the close button, a backdrop click, or Escape. The panel slides in from the right (held still under prefers-reduced-motion).

Open drawer
<button class="ds-button ds-button--primary" id="drawerOpen">Open drawer</button>
<div class="ds-drawer-overlay" id="demoDrawer">
  <div class="ds-drawer ds-drawer--right" role="dialog" aria-modal="true">
    <div class="ds-drawer__head">
      <h2 class="ds-drawer__title">Filters</h2>
      <button class="ds-button ds-drawer__close" data-drawer-close>Close</button>
    </div>
    <div class="ds-drawer__body"><p>Body content…</p></div>
  </div>
</div>
<script>
  const ov = document.querySelector("#demoDrawer");
  document.querySelector("#drawerOpen").onclick = () => ov.classList.add("is-open");
  const close = () => ov.classList.remove("is-open");
  ov.addEventListener("click", (e) => { if (e.target === ov) close(); });
  ov.querySelectorAll("[data-drawer-close]").forEach((b) => b.onclick = close);
  document.addEventListener("keydown", (e) => { if (e.key === "Escape") close(); });
</script>

React

The Drawer component portals to <body> and is controlled via open; it closes on Escape and a backdrop click. Pass placement, a heading, and optional footer actions.

<Drawer>
import { Drawer, Button } from "@diametral/design-system/react";

function Filters() {
  const [open, setOpen] = React.useState(false);
  return (
    <>
      <Button variant="primary" onClick={() => setOpen(true)}>Open drawer</Button>
      <Drawer
        open={open}
        onClose={() => setOpen(false)}
        placement="right"
        heading="Filters"
        footer={<Button variant="primary" onClick={() => setOpen(false)}>Apply</Button>}
      >
        <p>Body content…</p>
      </Drawer>
    </>
  );
}