Skip to content

Drawer <l-drawer>

Drawers display supplementary content in a panel that slides in from a screen edge. Commonly used for navigation menus, filters, and detail views without leaving the current page.

HTML tag<l-drawer>
Native
Progressive
Plain
Shadow-DOM
Shadow-DOM Custom Element

Options

Placement

Set placement to the edge the drawer slides from — start (default, inline-start), end (inline-end), top (block-start), or bottom (block-end). Open with command="--show" on a trigger button; the buttons below open one drawer per edge.

This drawer slides in from the start.

This drawer slides in from the top.

This drawer slides in from the bottom.

This drawer slides in from the end.

Code
html
<button
  type="button"
  class="l-button"
  command="--show"
  commandfor="drawer-end"
>
  <l-icon name="lucide:panel-right"></l-icon>
  End
</button>

<l-drawer
  id="drawer-end"
  title="Drawer"
  placement="end"
>
  <button
    slot="close"
    type="button"
    class="l-close"
    data-appearance="ring"
    aria-label="Close"
    command="--hide"
    commandfor="drawer-end"
  ></button>
  <p>This drawer slides in from the end.</p>
</l-drawer>

Inset

Add inset to float the drawer away from the viewport edges with a uniform gap and rounded corners. Tune the gap with the --inset-gap CSS custom property. Works with every placement — the buttons below open one drawer per edge.

This drawer floats away from the edges with rounded corners.

This drawer floats away from the edges with rounded corners.

This drawer floats away from the edges with rounded corners.

This drawer floats away from the edges with rounded corners.

Code
html
<button
  type="button"
  class="l-button"
  command="--show"
  commandfor="drawer-inset"
>
  <l-icon name="lucide:panel-right"></l-icon>
  End
</button>

<l-drawer
  id="drawer-inset"
  title="Drawer"
  placement="end"
  inset
>
  <button
    slot="close"
    type="button"
    class="l-close"
    data-appearance="ring"
    aria-label="Close"
    command="--hide"
    commandfor="drawer-inset"
  ></button>
  <p>This drawer floats away from the edges with rounded corners.</p>
</l-drawer>

Light dismiss

Add light-dismiss to close when the backdrop is clicked.

Click the backdrop or press Escape to close.

Code
html
<button
  type="button"
  class="l-button"
  command="--show"
  commandfor="drawer-light-dismiss"
>
  Open drawer
</button>

<l-drawer
  id="drawer-light-dismiss"
  title="Drawer"
  light-dismiss
>
  <button
    slot="close"
    type="button"
    class="l-close"
    data-appearance="ring"
    aria-label="Close"
    command="--hide"
    commandfor="drawer-light-dismiss"
  ></button>
  <p>Click the backdrop or press Escape to close.</p>
</l-drawer>

Examples

Mobile navigation menu with link items.

Code
html
<button
  type="button"
  class="l-button"
  command="--show"
  commandfor="drawer-nav"
>
  Menu
</button>

<l-drawer
  id="drawer-nav"
  title="Navigation"
>
  <button
    slot="close"
    type="button"
    class="l-close"
    data-appearance="ring"
    aria-label="Close"
    command="--hide"
    commandfor="drawer-nav"
  ></button>
  <nav>
    <ul class="flex flex-col gap-1">
      <li>
        <a
          href="#"
          class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium hover:bg-gray-100"
          >Home</a
        >
      </li>
      <li>
        <a
          href="#"
          class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium hover:bg-gray-100"
          >Products</a
        >
      </li>
      <li>
        <a
          href="#"
          class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium hover:bg-gray-100"
          >Orders</a
        >
      </li>
      <li>
        <a
          href="#"
          class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium hover:bg-gray-100"
          >Customers</a
        >
      </li>
      <li>
        <a
          href="#"
          class="flex items-center gap-3 rounded-lg px-3 py-2 text-sm font-medium hover:bg-gray-100"
          >Settings</a
        >
      </li>
    </ul>
  </nav>
</l-drawer>

Filters

End-side filter panel with a footer for actions.

Category
Price range
Code
html
<button
  type="button"
  class="l-button"
  command="--show"
  commandfor="drawer-filters"
>
  Filters
</button>

<l-drawer
  id="drawer-filters"
  title="Filters"
  placement="end"
  style="--size: 380px"
>
  <button
    slot="close"
    type="button"
    class="l-close"
    data-appearance="ring"
    aria-label="Close"
    command="--hide"
    commandfor="drawer-filters"
  ></button>
  <div class="flex flex-col gap-6">
    <fieldset>
      <legend class="text-sm font-medium mb-2">Category</legend>
      <div class="flex flex-col gap-2">
        <label class="flex items-center gap-2 text-sm"
          ><input
            type="checkbox"
            checked
          />
          Electronics</label
        >
        <label class="flex items-center gap-2 text-sm"><input type="checkbox" /> Clothing</label>
        <label class="flex items-center gap-2 text-sm"><input type="checkbox" /> Books</label>
      </div>
    </fieldset>
    <fieldset>
      <legend class="text-sm font-medium mb-2">Price range</legend>
      <div class="flex flex-col gap-2">
        <label class="flex items-center gap-2 text-sm"
          ><input
            type="radio"
            name="price"
            checked
          />
          All prices</label
        >
        <label class="flex items-center gap-2 text-sm"
          ><input
            type="radio"
            name="price"
          />
          Under $50</label
        >
        <label class="flex items-center gap-2 text-sm"
          ><input
            type="radio"
            name="price"
          />
          $50 – $100</label
        >
        <label class="flex items-center gap-2 text-sm"
          ><input
            type="radio"
            name="price"
          />
          Over $100</label
        >
      </div>
    </fieldset>
  </div>
  <menu slot="footer">
    <button
      type="button"
      class="l-button"
      command="--hide"
      commandfor="drawer-filters"
    >
      Cancel
    </button>
    <button
      type="button"
      class="l-button"
      data-variant="primary"
    >
      Apply
    </button>
  </menu>
</l-drawer>

Accessibility

Criteria

Role

Rendered as a native <dialog> in the shadow root — built-in dialog role and modal semantics

WCAG4.1.2
RGAA7.1
Accessible name

The title property is rendered as an <h2> inside the drawer header

WCAG4.1.2
RGAA11.1
Focus management

Focus is trapped inside the modal; moves to the first focusable element on open

WCAG2.4.3
RGAA10.7
Focus restoration

Focus returns to the trigger element when the drawer closes

WCAG2.4.3
Close button

Consumer provides the close button via slot="close" with aria-label="Close"

WCAG2.4.6
Motion

Slide animation respects prefers-reduced-motion

WCAG2.3.3

Keyboard interactions

Escape
Closes the drawer
Tab
Cycles focus through focusable elements inside the drawer
ShiftTab
Cycles focus backward through focusable elements inside the drawer

API reference

Importing

js
import 'luxen-ui/drawer';

Attributes & Properties

placement'start' | 'end' | 'top' | 'bottom' | undefinedProperty
Edge the drawer slides in from. Defaults to the start (inline-start) edge.
insetbooleandefault:falseProperty
Detach the drawer from the viewport edges, floating it with a uniform gap and rounded corners.
titlestringProperty
Dialog title rendered in the header and used as the dialog's accessible name.
openbooleandefault:falseProperty
Whether the dialog is open.
light-dismissbooleandefault:falseProperty
Close when the backdrop is clicked.
without-headerbooleandefault:falseProperty
Hide the header entirely (title and close slot).

Commands

Open and close the drawer by toggling its open property, or via the Invoker Commands API from any light-DOM button. Custom commands must start with --.

INFO

The Invoker Commands API is ✓ Baseline Newly Available (since 2025-12-12). For older browser versions, load the invokers-polyfill once at app startup:

js
import 'invokers-polyfill';
--showCommand
Sets open = true.
--hideCommand
Sets open = false.

Events

showcancelableEvent
Fired when the drawer is about to open. Cancelable — call event.preventDefault() to keep it closed.
after-showEvent
Fired after the open animation completes. Not cancelable.
hidecancelableEvent
Fired when the drawer is about to close. Cancelable — call event.preventDefault() to keep it open.
after-hideEvent
Fired after the close animation completes. Not cancelable.

Slots

(default)Slot
Body content.
titleSlot
Custom heading element. Overrides the default <h2> rendered from the title property. Also provides the dialog's accessible name.
closeSlot
Close button (typically <button class="l-close">).
footerSlot
Footer actions.

CSS parts

dialogPart
The native <dialog> element.
headerPart
The header wrapper containing the title and close slot.
titlePart
The drawer title heading.
bodyPart
The body wrapper around the default slot.
footerPart
The footer wrapper around the footer slot.

CSS custom properties

--sizedefault:320pxCustom property
Drawer size on the axis perpendicular to its edge (width for start/end, height for top/bottom).
--border-radiusdefault:6pxCustom property
Drawer border radius on the inner edges (all corners when inset).
--inset-gapdefault:1remCustom property
Gap between the drawer and the viewport edges when inset is set.
--shadowCustom property
Drop shadow applied to the floating panel when inset is set. Set to none to remove it.
--show-durationdefault:200msCustom property
Open transition duration.
--hide-durationdefault:200msCustom property
Close transition duration.
--backdropCustom property
Backdrop color.
--widthdefault:31remCustom property
Dialog width.
--paddingdefault:1.5remCustom property
Padding applied to the header, footer, and inline-padding of the body. Set to 0 to remove all internal spacing (e.g. for edge-to-edge media).
--backdrop-blurdefault:0Custom property
Backdrop blur amount (any CSS length). 0 means no blur; set e.g. 4px for a subtle frost.