GitHub

Side Dialog

A slide-in drawer / side sheet. Full-height panel fixed to a side edge, with its own backdrop, focus trap, Esc-to-close, and focus restore — the modal mechanics of a dialog with edge-anchored layout.

Stable wc import '@esa/ecology/esa-side-dialog';

Preview

Drawer body content goes here. It scrolls if it overflows, with the header and footer pinned.

Use it for filters, detail panes, and create/edit forms that don't warrant a full page.

<button id="open-sd">Open drawer</button>
<esa-side-dialog id="sd" heading="Filters" position="right">
  <p>Drawer body content…</p>
  <button slot="footer">Apply</button>
</esa-side-dialog>

Positions & sizes

Slides from left or right; width via size (sm 320 · md 400 · lg 520).

<esa-side-dialog position="left" size="sm" heading="Left, sm"></esa-side-dialog>

API

PropTypeDefaultDescription
heading string Title shown in the header.
position 'left' | 'right' 'right' Edge the drawer slides in from.
size 'sm' | 'md' | 'lg' 'md' Panel width — 320 / 400 / 520px.
show-close-button boolean true Render the header close (✕) button.

Methods

PropTypeDefaultDescription
show() method Open the drawer.
close() method Close it (restores focus, emits `close`).

Events

EventTypeDefaultDescription
close CustomEvent Fired when the drawer closes (Esc, backdrop, or close button).

Accessibility

  • role="dialog" + aria-modal; labelled by the heading.
  • Focus is trapped within the panel; Tab/Shift+Tab cycle, Esc closes, and focus is restored to the trigger on close.
  • The backdrop click and the ✕ button both close.

Theming surface

Every public token this component reads, extracted from its source at build time. The Resolves to column walks each token's real lineage — component → semantic → primitive → raw value — so you can see exactly where re-pointing it lands. A spoke re-skins by overriding these in its theme-<slug>.css; component internals are never edited. No hook for what you need? File it with /request-lego.

TokenTierResolves to
--backdrop-filter component none
--side-dialog-bg component #fcfcfc via --color-surface--color-gray-1
--side-dialog-border-color component #cecece via --color-border--color-gray-7
--side-dialog-inset component 16px
--side-dialog-radius component 0.5rem via --radius-200
--side-dialog-width component 400px
--side-dialog-width-lg component 520px
--side-dialog-width-sm component 320px
--side-dialog-color ad-hoc #202020 via --color-text-primary--color-gray-12
--color-backdrop semantic rgba(0, 0, 0, 0.5) via --color-black-a-7
--color-surface-sunken semantic #f0f0f0 via --color-gray-3
--color-text-muted semantic #838383 via --color-gray-10
--color-text-primary semantic #202020 via --color-gray-12
--type-size-400 semantic clamp(1rem, 0.88rem + 0.6vw, 1.25rem)
--font-weight-semibold primitive 550
--radius-100 primitive 0.25rem
--shadow-400 primitive 0 8px 32px -8px rgba(0, 0, 0, 0.08)
--spacing-300 primitive 0.75rem
--spacing-400 primitive 1rem
--spacing-500 primitive 1.5rem
--z-modal primitive 400
--z-modal-backdrop primitive 300