Disclosures
Drawer
An edge-anchored panel that slides in over the page, built on the native <dialog> element and the browser's top layer.
Import
import { Drawer } from "@loamui/core";Usage
Every example has a CSStab. That’s the real, complete stylesheet for the component: plain, static CSS, with nothing running in the browser.
Basic usage
Compose the drawer from parts. The Panel is a native <dialog> opened with showModal(): top layer, backdrop, focus containment, Escape and focus restore all come from the browser. A Drawer is a Modal pinned to an edge with a slide transition.
Sides
side anchors the panel to an edge and picks the slide direction. It is logical (start / end / top / bottom), so start and end follow the writing mode: inline-start is the left in LTR, the right in RTL.
Sizes
size sets the panel's short axis: the width for start / end, the height for top / bottom. The long axis always fills the viewport.
Guidance
When to use it
- For navigation and secondary content that shouldn't take over the whole screen: a mobile menu, a filter panel, a details side-sheet.
- When the surrounding page context should stay visible behind a dimmed backdrop, and the panel is casually dismissible.
- On narrow screens, to hold navigation that sits in a persistent sidebar on wider ones.
When not to
- For a focused, must-answer task or a destructive confirmation, use Modal, a dialog centred on the decision, not parked at an edge.
- For a small set of actions opened from a control, use Menu; for supplementary content anchored to a trigger, use Popover.
- For primary navigation that fits on wide screens, use a persistent sidebar or nav bar rather than hiding it behind a trigger.
Accessibility
- Built on the native <dialog> opened with showModal(): the browser provides the top layer, ::backdrop, real focus containment, Escape handling, and restores focus to the trigger on close, none of it re-implemented in JavaScript.
- Drawer.Title and Drawer.Description automatically label and describe the dialog via aria-labelledby / aria-describedby.
- Light dismiss (clicking the backdrop) uses the closedby attribute where supported, with a small feature-detected coordinate-check fallback elsewhere: no polyfills, per the browser support policy.
- The slide transition lives inside prefers-reduced-motion: no-preference, so users who ask for reduced motion get an instant open with no movement.
- A forced-colors border keeps the panel edge visible when background colours are overridden; body scroll is locked while open.
How it works
Anchor to a logical edge
side is logical, not physical: start and end follow the writing mode so a start drawer opens from the left in LTR and the right in RTL, matching where users expect the back edge to be. Reach for top / bottom for sheets: a bottom sheet is the thumb-friendly choice for actions on touch devices.
A drawer is dismissible by nature
Unlike an alert dialog, a drawer light-dismisses: clicking the backdrop or pressing Escape closes it. That is the right contract for navigation and browsing. Never put a decision the user must not dismiss by accident in a drawer; use Modal's alert for that.
Always render a Title
Drawer.Title labels the dialog via aria-labelledby; it is what screen readers announce on open. A drawer used purely for navigation should still carry a Title (for example "Navigation") so its purpose is announced, even if you hide it visually.
Keep the trigger where the focus returns
The browser restores focus to the trigger when the drawer closes. Keep a single, stable trigger (a hamburger button) rather than swapping it out while open, so keyboard and screen-reader users land back where they started.
Parts
Drawer.Root
Groups the parts and owns open state (controlled or uncontrolled). Renders no element of its own.
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. |
defaultOpen | boolean | false | Uncontrolled initial state. |
onOpenChange | (open: boolean) => void | — | Fires when the drawer opens or closes. |
Drawer.Trigger
A LoamUI Button that opens the drawer.
| Prop | Type | Default | Description |
|---|---|---|---|
render | RenderProp | — | Substitute your own action element (an icon button); the wiring merges on. |
...others | ButtonHTMLAttributes | — | Forwarded to the button. |
Drawer.Panel
The native <dialog>. side anchors it to an edge and sets the slide direction; size sets the short-axis extent (width for start/end, height for top/bottom).
| Prop | Type | Default | Description |
|---|---|---|---|
side | "start" | "end" | "top" | "bottom" | "start" | Edge to anchor to. |
size | "sm" | "md" | "lg" | "md" | Short-axis extent. |
Drawer.Title / Drawer.Description
Label and describe the dialog for assistive technology.
Drawer.Close
A LoamUI Button that closes the drawer; compose as many as you need (a footer action, a header ×). Supports render like the Trigger.