@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.

Morph Transport

Attach a morph engine and pass the trigger to show() for a spring-driven container transform into the real modal dialog. Any element can be the source — the card grows into one panel, the button into another, each with its own engine, and closing springs each back to where it came from. Click the scrim during the flight to reverse it in place.

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.

Container transform

Closed in flight. Modal at rest.

The spring renders this dialog in normal flow while it travels. On the final frame, Dialog Panel promotes it with showModal() so focus trapping and Escape behavior stay native.

Same trick, smaller seed

Grown from a button.

A separate panel with its own engine. The spring measures whatever you hand to show() — pill radius, gold surface and all — and gives the geometry back on the way out.

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