Liking cljdoc? Tell your friends :D

x-drawer

A modal overlay panel that slides in from any edge of the screen (left, right, top, or bottom). The drawer is always a temporary modal overlay: it always shows a backdrop, always traps focus, and always dismisses on Escape or backdrop click.

Tag

<x-drawer placement="right" label="Drawer">
  <div slot="header">Header content</div>
  Body content goes here
  <div slot="footer">Footer content</div>
</x-drawer>

Observed Attributes

AttributeTypeDefaultDescription
openboolabsentShows the drawer when present
placementenum"right"Edge: left \| right \| top \| bottom
labelstring"Drawer"aria-label for the dialog panel

Properties

PropertyTypeReflects attribute
openbooleanopen
placementstringplacement
labelstringlabel

Methods

MethodDescription
show()Sets open attribute
hide()Removes open attribute
toggle()Flips open state

Events

EventCancelableDetail
x-drawer-togglefalse{ open: boolean }
x-drawer-dismissfalse{ reason: "escape" \| "backdrop" }

x-drawer-toggle fires whenever the open state changes (open or close), including programmatic changes.

x-drawer-dismiss fires only when the drawer is closed by a user gesture (Escape key or backdrop click).

Slots

SlotDescription
headerNamed — title area, close button, etc.
(default)Scrollable body content
footerNamed — action buttons

There is no built-in close button. Provide a close affordance in the header slot.

CSS Parts

PartDescription
backdropOverlay scrim behind the panel
panelThe drawer container (dialog)
headerHeader slot wrapper
bodyDefault slot wrapper (scrollable)
footerFooter slot wrapper

CSS Custom Properties

PropertyDefaultDescription
--x-drawer-size20remPanel width (left/right) or height (top/bottom)
--x-drawer-bgCanvasPanel background
--x-drawer-fgCanvasTextPanel foreground
--x-drawer-backdroprgb(0 0 0 / 0.4)Scrim color
--x-drawer-shadow0 8px 24px rgb(0 0 0 / 0.18)Panel box shadow
--x-drawer-duration200msSlide animation duration
--x-drawer-easingeaseSlide animation easing
--x-drawer-z1000z-index base (panel is z+1)
--x-drawer-header-padding1rem 1.25remHeader slot wrapper padding
--x-drawer-body-padding1rem 1.25remBody slot wrapper padding
--x-drawer-footer-padding0.75rem 1.25remFooter slot wrapper padding
--x-drawer-bordercolor-mix(in srgb, currentColor 12%, transparent)Separator border between header/body/footer

Animation

The panel slides in from its placement edge:

  • left: translateX(-100%)translateX(0)
  • right: translateX(100%)translateX(0)
  • top: translateY(-100%)translateY(0)
  • bottom: translateY(100%)translateY(0)

Animation is disabled when prefers-reduced-motion: reduce is set.

Theming

Default colors use the CSS system colors Canvas and CanvasText, which automatically adapt to the OS light/dark mode preference. Override via CSS custom properties on the element or any ancestor.

Accessibility

  • The panel has role="dialog" and aria-modal="true".
  • aria-label on the panel is set from the label attribute.
  • Focus is trapped inside the panel while it is open: Tab cycles forward through focusable elements, Shift+Tab cycles backward.
  • On open, focus moves to the first focusable element in the panel (or the panel itself if none exist).
  • On close, focus returns to the element that was focused before the drawer opened.
  • Pressing Escape closes the drawer.
  • Clicking the backdrop closes the drawer.

Usage Examples

Basic usage

<x-drawer id="my-drawer">
  <div slot="header">
    <span>Task Details</span>
    <button onclick="document.getElementById('my-drawer').hide()">✕</button>
  </div>
  <p>Drawer body content.</p>
  <div slot="footer">
    <button onclick="document.getElementById('my-drawer').hide()">Done</button>
  </div>
</x-drawer>

<button onclick="document.getElementById('my-drawer').show()">Open drawer</button>

Left placement

<x-drawer placement="left" label="Navigation">
  <nav slot="header">Navigation</nav>
  <ul>
    <li><a href="/">Home</a></li>
    <li><a href="/about">About</a></li>
  </ul>
</x-drawer>

Custom size

<x-drawer style="--x-drawer-size: 32rem;" placement="right">
  Wide drawer content
</x-drawer>

Listening to events

const drawer = document.querySelector('x-drawer');

drawer.addEventListener('x-drawer-toggle', (e) => {
  console.log('Drawer is now', e.detail.open ? 'open' : 'closed');
});

drawer.addEventListener('x-drawer-dismiss', (e) => {
  console.log('Dismissed by', e.detail.reason); // "escape" | "backdrop"
});

Programmatic control

drawer.show();    // open
drawer.hide();    // close
drawer.toggle();  // flip

drawer.open = true;   // same as show()
drawer.open = false;  // same as hide()

drawer.placement = 'bottom';
drawer.label = 'Filter options';

Can you improve this documentation?Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close