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.
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.
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).
<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.
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>
</>
);
}