Free pack

Dialog — <mv-dialog>

Animated native <dialog> modal; also covers Alert Dialog (persistent), Sheet (4 sides) and a mobile Drawer with swipe to close.

CategoryOverlays
TypeWeb Component (<mv-dialog>)
Statusstable
Keywordsmodal, dialog, alert-dialog, sheet, drawer, swipe

When to use

Avoid when

Install

node scripts/add.mjs dialog --out ./src/marvelous

AI agent with the Marvelous UI MCP server: install_components({ slugs: ["dialog"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Files copied (dependencies included): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/motion.js, components/dialog/dialog.js, components/dialog/dialog.css.

Usage

Canonical markup — start from it and customize with attributes, data-* and CSS variables:

<div style="display:flex;flex-wrap:wrap;gap:.75rem;justify-content:center">
  <mv-dialog>
    <button class="mv-button" data-mv-open>Edit profile</button>
    <dialog>
      <button class="mv-dialog-close" data-mv-close aria-label="Close"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
      <header class="mv-dialog-header">
        <h2 class="mv-dialog-title">Edit profile</h2>
        <p class="mv-dialog-description">Changes are saved when you click Save.</p>
      </header>
      <form method="dialog" style="display:grid;gap:.75rem">
        <label style="display:grid;gap:.35rem;font-size:.875rem">Name
          <input value="Ada Lovelace" style="height:2.25rem;padding:0 .75rem;border:1px solid var(--mv-input);border-radius:var(--mv-radius-md);background:var(--mv-bg)">
        </label>
        <div class="mv-dialog-footer">
          <button type="button" class="mv-button" data-variant="outline" data-mv-close>Cancel</button>
          <button class="mv-button" value="save">Save</button>
        </div>
      </form>
    </dialog>
  </mv-dialog>

  <mv-dialog persistent>
    <button class="mv-button" data-variant="destructive" data-mv-open>Delete…</button>
    <dialog style="--mv-dialog-width:26rem">
      <header class="mv-dialog-header">
        <h2 class="mv-dialog-title">Delete project?</h2>
        <p class="mv-dialog-description">This action can’t be undone. All data will be lost.</p>
      </header>
      <div class="mv-dialog-footer">
        <button class="mv-button" data-variant="outline" data-mv-close="cancel">Cancel</button>
        <button class="mv-button" data-variant="destructive" data-mv-close="confirm">Delete</button>
      </div>
    </dialog>
  </mv-dialog>

  <mv-dialog>
    <button class="mv-button" data-variant="outline" data-mv-open>Side panel</button>
    <dialog data-variant="sheet" data-side="right">
      <button class="mv-dialog-close" data-mv-close aria-label="Close"><svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
      <header class="mv-dialog-header">
        <h2 class="mv-dialog-title">Filters</h2>
        <p class="mv-dialog-description">Slides in from the right.</p>
      </header>
    </dialog>
  </mv-dialog>

  <mv-dialog swipe>
    <button class="mv-button" data-variant="outline" data-mv-open>Mobile drawer</button>
    <dialog data-variant="sheet" data-side="bottom">
      <header class="mv-dialog-header">
        <h2 class="mv-dialog-title">Drawer</h2>
        <p class="mv-dialog-description">Swipe down to close it.</p>
      </header>
      <div style="height:30vh"></div>
    </dialog>
  </mv-dialog>
</div>

API

Attributes

NameTypeDescription
openbooleanOpens/closes the modal.
persistentbooleanAlert mode: no closing via Escape or outside click, role=alertdialog.
swipebooleanSwipe to close (sheets / drawers).

Methods

NameDescription
show()Opens as a modal.
close(returnValue?)Closes with a return value.

Events

NameDescription
mv-before-openCancelable (preventDefault).
mv-openAfter opening.
mv-closedetail.returnValue: value of the [data-mv-close] button, or “dismiss” / “swipe”.

Content structure

NameDescription
[data-mv-open]Internal trigger; for an external one: data-mv-open="#id".
<dialog>Content; data-variant="sheet" + data-side="right|left|top|bottom".
[data-mv-close]Closes; its value becomes returnValue.

CSS classes

NameDescription
mv-dialog-header / -title / -description / -footer / -closeContent layout.

CSS variables

NameDefaultDescription
--mv-dialog-width30remWidth (sheet: 24rem).
--mv-dialog-radiusRadius.
--mv-dialog-backdrop-blur3pxBackdrop blur.

Accessibility

Focus trapped and restored by the native <dialog>, inert page, Escape. aria-labelledby/-describedby wired automatically from .mv-dialog-title / .mv-dialog-description.