This page features interactive demos and side-by-side code samples that need at least 340 pixels of horizontal space. Please widen your browser window, or rotate your device, to continue.
Component <neo-dialog> is a modal dialog wrapping the platform <dialog> element. The host wires trigger, close, and aria plumbing; the browser owns top-layer rendering, focus trap, scroll lock, and Esc. No portal: markup stays in light DOM so kit CSS themes it directly.
Default
Non-dismissible
Custom surface
DeactivateRenameDuplicateDelete
The preview routes through the in-browser server simulator. Its current Settings (network latency, a non-200 response, or an unreachable server) are in effect, so the live preview can look like it is misbehaving. Adjust them in the Settings panel.
New state Toggle autoplay
Open dialog
HTMLCSS
The selected state's markup and its scoped CSS. The CSS is wrapped in <style>@scope { ... }</style> and applies to the preview only. Edits change the preview above, applied live while Sync is on, or when you click Patch or Replace. Patch morphs the preview; Replace swaps it outright.
Signals
Datastar signals declared in the selected state's markup. Change a value to drive the preview, applied live while Sync is on, or when you click Patch.
<neo-dialog>
<neo-button data-neo-dialog-trigger>Open dialog</neo-button>
<dialog>
<header data-neo-dialog-header>
<h2 data-neo-dialog-title>Are you absolutely sure?</h2>
<p data-neo-dialog-description>
This action cannot be undone. This will permanently delete
your account and remove your data from our servers.
</p>
</header>
<footer data-neo-dialog-footer>
<neo-button data-neo-dialog-close>Cancel</neo-button>
<neo-button variant="primary" data-neo-dialog-close>Continue</neo-button>
</footer>
</dialog>
</neo-dialog><neo-dialog dismissible="false">
<neo-button data-neo-dialog-trigger>Delete project</neo-button>
<dialog>
<header data-neo-dialog-header>
<h2 data-neo-dialog-title>Delete project?</h2>
<p data-neo-dialog-description>This will remove all builds, secrets, and members. The project name cannot be reused for 30 days.</p>
</header>
<footer data-neo-dialog-footer>
<neo-button data-neo-dialog-close>Cancel</neo-button>
<neo-button variant="danger" data-neo-dialog-close>Delete</neo-button>
</footer>
</dialog>
</neo-dialog><neo-dialog class="dialog-custom-surface">
<neo-button data-neo-dialog-trigger>Open frost glass</neo-button>
<dialog>
<header data-neo-dialog-header>
<h2 data-neo-dialog-title>Frost glass surface</h2>
<p data-neo-dialog-description>Two stacked blurs: the <code>::backdrop</code> frosts the page behind the modal at 6px (with a soft 18% black tint), and the dialog surface adds another 22px on top of its own 42% dark wash. The page reads through both layers as a deep frosted scene: soft outside the dialog, denser within.</p>
</header>
<footer data-neo-dialog-footer>
<neo-button data-neo-dialog-close>Close</neo-button>
<neo-button variant="primary" data-neo-dialog-close>OK</neo-button>
</footer>
</dialog>
</neo-dialog>.dialog-custom-surface {
--neo-dialog-bg: rgba(15, 16, 22, 0.42);
--neo-dialog-color: #f4f4f5;
--neo-dialog-border-color: rgba(255, 255, 255, 0.12);
--neo-dialog-blur: 22px;
--neo-dialog-overlay-bg: rgba(0, 0, 0, 0.18);
--neo-dialog-overlay-blur: 6px;
--muted: rgba(244, 244, 245, 0.65);
}
For must-decide flows, set dismissible="false": backdrop clicks and Esc are ignored, so the user must pick an action. Pair it with a clearly destructive primary button.
A Datastar app can fat-morph an open dialog's body at any moment; the dialog stays mounted and open and focus survives.
A <neo-elastic> wrapper around the body animates the dialog's height between the two layouts.
Autoplay cycles the states below to simulate the server-driven morphs.
Initial
Different content
DeactivateRenameDuplicateDelete
The preview routes through the in-browser server simulator. Its current Settings (network latency, a non-200 response, or an unreachable server) are in effect, so the live preview can look like it is misbehaving. Adjust them in the Settings panel.
New state Toggle autoplay
What's new
HTMLCSS
The selected state's markup and its scoped CSS. The CSS is wrapped in <style>@scope { ... }</style> and applies to the preview only. Edits change the preview above, applied live while Sync is on, or when you click Patch or Replace. Patch morphs the preview; Replace swaps it outright.
Signals
Datastar signals declared in the selected state's markup. Change a value to drive the preview, applied live while Sync is on, or when you click Patch.
Load the body on every open. A [data-neo-async-placeholder] child holds skeleton bars; opening posts to the server, whose response morph-patches real content in to replace it.
On close the host reinstates the placeholder, so each open shows it again until the new request resolves.
requestCancellation aborts an in-flight request when the user closes mid-load.
Async load that shows a failure state and a retry button when the request keeps failing.
The loader lives in the dialog's [data-neo-async-placeholder] slot, so close/reopen restores it; on success the server morphs <div id="<host-id>-body"> in place.
Once Datastar exhausts its retry budget, a failure view with a [data-neo-popover-async-retry] button replaces the body without closing the dialog.
Builds Morpheus, the server-driven web component kit this site is built with.
Daniel Scharkov
Co-maker of Morpheus · daniel.scharkov@example.com
Works on Morpheus with his brother Roman; the two ship it together.
Loading states only show with simulated delay. Raise network latency or handler delay in the Settings panel.
Load profile
Couldn't load content.Retry
Opening streams progress patches over time. Each patch morphs the steps wrapper inside a <neo-elastic>, which animates the dialog's height as rows are added.
The final patch swaps in a <neo-button data-neo-dialog-close> so the user can dismiss only after the simulated job finishes.