@magic-spells/dialog-panel

Dialog
Panel

A lightweight web component wrapping native <dialog> with state-driven animations. Browser-native focus trapping, escape handling, and top-layer stacking — no dependencies needed.

Install npm i @magic-spells/dialog-panel
JS (gzip) 1.26 KB
CSS (gzip) 0.60 KB
Dependencies 0

Markup

Drop in a <dialog-panel> wrapping a native <dialog>. The backdrop is auto-created. Close buttons use data-action-hide-dialog.

<dialog-panel id="my-dialog"> <dialog aria-labelledby="title"> <h2 id="title">Hello</h2> <p>Your dialog content here.</p> <button data-action-hide-dialog>Close</button> </dialog> </dialog-panel> <!-- Show it from JavaScript --> <script> const panel = document.querySelector('#my-dialog') panel.show(triggerElement) // opens with animation panel.hide() // closes with animation </script>

Basic Dialog

Click to open. Close via the button, Escape key, or clicking the backdrop. Focus returns to the trigger element automatically.

State Machine

The component moves through four states, each mapped to a CSS attribute selector. Animations are pure CSS transitions driven by [state] changes.

hidden
→ show()
showing
→ RAF
shown
→ hide()
hiding
→ close()
Live state tracker

Events & Lifecycle

Four custom events fire at each stage. beforeShow and beforeHide are cancelable — call preventDefault() to block the transition.

Event Cancelable When
beforeShow yes Before showModal() is called
shown no After show transition completes
beforeHide yes Before hide transition starts
hidden no After dialog is closed and hidden
Event log
Events

Cancel Prevention

Attach a beforeHide listener and call preventDefault() to block the dialog from closing — useful for unsaved-changes confirmations or required forms.

Try closing this dialog

Nested Dialogs

Place a <dialog-panel> inside another dialog. Each gets its own backdrop in the top layer. stopPropagation prevents the inner close from dismissing the outer.

Positions

Set position="top|bottom|left|right" to slide the panel in from an edge instead of fading from center. Useful for cart drawers, mobile menus, action sheets, and predictive search.

Features

Native <dialog>

Built on showModal() for free focus trapping, escape handling, and top-layer stacking.

CSS-Only Animation

State attribute drives transitions. No JS animation logic — override with your own CSS.

Animated Backdrop

Cross-browser animated backdrop via <dialog-backdrop>, auto-created if missing.

Cancelable Events

Block show or hide with preventDefault() on beforeShow / beforeHide.

Nesting Support

Stack dialogs naturally. Each layer gets its own backdrop with proper z-ordering.

Focus Return

Automatically returns focus to the trigger element when the dialog closes.

Welcome

This dialog uses the native <dialog> element with showModal() for built-in accessibility.

Try pressing Escape or clicking the backdrop to close.

State Tracking

Watch the state diagram update as this dialog opens and closes.

Events Demo

Open and close this dialog to see the lifecycle events fire in the log below.

Unsaved Changes

This dialog blocks the first close attempt. The second attempt will succeed.

Try pressing Escape, clicking the backdrop, or the close button.

Outer Dialog

This is the outer dialog. Click the button below to open a nested dialog on top of this one.

The inner dialog's backdrop will appear above this dialog in the top layer.

Inner Dialog

This is the inner (nested) dialog.

The backdrop correctly covers the outer dialog. Closing this won't dismiss the parent.

Recent searches
  • linen overshirt
  • ceramic mug set
  • shipping policy
  • gift cards

Discard changes?

You have unsaved edits. This can't be undone.

Your Cart

IMG
Linen Overshirt Sand · Medium Qty 1
$148.00
IMG
Ceramic Mug Set Bone · Set of 2 Qty 1
$64.00
IMG
Wool Throw Ochre · 50×60in Qty 2
$220.00