motion-dialog
Modal dialog with spring-physics animation. Slides up on open, springs back down on close. Built on the native <dialog> element for top-layer
stacking and keyboard accessibility.
Preview
Spring dialog
Slides up with spring physics. The backdrop fades in simultaneously. Press Esc or use the button to close.
No backdrop
Add no-backdrop to remove the dimmed overlay. The dialog floats without any overlay.
No backdrop
Floating dialog with no dimmed overlay. Press Esc or use the button to close.
Light dismiss
Add light-dismiss to let users close by clicking the backdrop. By default, only Esc and explicit close actions work.
Light dismiss
Click the backdrop or press Esc to close. Without light-dismiss, only Esc and an explicit close button work.
Import
import 'motion-components/motion-dialog' // just this one
import 'motion-components' // or the whole libraryUsage
<button onclick="document.querySelector('#dlg').show()">Open</button>
<motion-dialog id="dlg">
<h2>Dialog title</h2>
<p>Dialog content goes here.</p>
<button onclick="this.closest('motion-dialog').close()">Close</button>
</motion-dialog>Declarative open
Set the open attribute to control the dialog from markup or frameworks that bind attributes:
<!-- opens on mount -->
<motion-dialog open>
<p>Shown immediately on page load.</p>
</motion-dialog>Listening for open and close
The motion-open event fires when the dialog opens, as the entrance animation starts. The motion-close event fires after the exit animation completes. Use them to sync state:
import type { MotionDialog } from 'motion-components'
const dialog = document.querySelector<MotionDialog>('motion-dialog')!
dialog.addEventListener('motion-open', () => {
console.log('dialog opened')
})
dialog.addEventListener('motion-close', () => {
console.log('dialog closed')
})Properties
| Attribute | Property | Type | Default | Description |
|---|---|---|---|---|
| | | boolean | false | Opens the dialog when present; reflects to attribute |
| | | number | 0.5 | Spring duration for enter/exit animations, in seconds |
| | | number | 0.25 | Spring bounciness (0 = critically damped, higher = more elastic) |
| | | number | 40 | Initial vertical offset for the slide-up entrance, in pixels |
| | | boolean | false | When present, hides the dimmed/blurred overlay. The dialog floats without any overlay |
| | | boolean | false | When present, clicking the backdrop outside the panel closes the dialog |
CSS custom properties
Style the panel and backdrop without reaching into shadow DOM:
| Property | Type | Default | Description |
|---|---|---|---|
| | color | var(--mc-color-surface, Canvas) | Panel background |
| | color | var(--mc-color-text, CanvasText) | Panel text color |
| | length | 16px | Panel corner radius |
| | length | 2rem | Panel padding |
| | length | min(560px, 100vw - 2rem) | Maximum panel width |
| | length | calc(100dvh - 4rem) | Maximum panel height |
| | shadow | 0 8px 32px … | Panel box shadow. The default ends with a 1px ring in |
| | color | rgba(0, 0, 0, 0.48) | Backdrop overlay color |
| | filter | blur(6px) | Backdrop |
motion-dialog {
--mc-dialog-bg: #1a1a2e;
--mc-dialog-color: #e2e2ff;
--mc-dialog-radius: 24px;
--mc-dialog-backdrop-color: rgba(10, 10, 30, 0.6);
--mc-dialog-backdrop-blur: blur(12px);
}Methods
| Method | Description |
|---|---|
| | Opens the dialog with the entrance animation. |
| | Closes the dialog with the exit animation. |
Events
| Event | Description |
|---|---|
| | Fired when the dialog opens, as the entrance animation starts. Not fired when the dialog is reopened during its exit animation. Bubbles and is composed. |
| | Fired after the close animation completes. Bubbles and is composed. |
Accessibility
Uses the native <dialog> element opened via showModal(), which places it in the browser's top layer. Focus is
automatically trapped inside the dialog while open, and Esc always closes it. By default, clicking the backdrop does
not close the dialog. Add light-dismiss to enable that. Screen readers announce the dialog via the browser's built-in
role="dialog" and aria-modal semantics. With prefers-reduced-motion active, all animations are skipped
and the dialog appears instantly.