Skip to content

Dialog

Modal dialogs with focus trap and backdrop handling.

Add new user

Delete user


Are you sure you want to delete ?

Props


  • 🪟 Uses native HTML <dialog> element
  • 🔒 Built-in scroll lock when open
  • 🎯 Focus trap and focus management
  • 🎨 Animation support with custom overlay
<script lang="ts">
import { Dialog } from "melt/builders";
const dialog = new Dialog();
</script>
<button {...dialog.trigger}>
Open Dialog
</button>
<!-- Optional overlay for animations -->
<div {...dialog.overlay}></div>
<dialog {...dialog.content}>
Dialog content
</dialog>

Dialogs support smooth animations for both the content and backdrop. To enable animations, use the overlay element instead of the native ::backdrop pseudo-element.

<script lang="ts">
import { Dialog } from "melt/builders";
const dialog = new Dialog();
</script>
<button {...dialog.trigger}>
Open Dialog
</button>
<!-- Overlay with fade animation -->
<div {...dialog.overlay}></div>
<!-- Dialog with scale and fade animation -->
<dialog {...dialog.content}>
<h2>Hello!</h2>
<button onclick={() => dialog.open = false}>Close</button>
</dialog>
<style>
dialog {
width: 24rem;
background: white;
opacity: 0;
scale: 0.95;
transition: ease 300ms;
}
dialog::backdrop {
display: none;
}
dialog[data-open] {
opacity: 1;
scale: 1;
}
[data-melt-dialog-overlay] {
position: fixed;
width: 100%;
height: 100%;
background: black;
opacity: 0;
transition: ease 300ms;
}
[data-melt-dialog-overlay][data-open] {
opacity: 0.1;
}
</style>

When you set dialog.open = true:

  1. The overlay element shows using the Popover API
  2. The dialog element shows with showModal()
  3. A tick() occurs to update the data-open attribute
  4. CSS transitions animate the elements to their open state

When you set dialog.open = false:

  1. The data-open attribute is removed immediately
  2. CSS transitions animate elements to their closed state
  3. When transitions complete, the dialog and overlay are closed
  • Transition Duration: Ensure the transitionend event fires by using CSS transitions with non-zero duration
  • Backdrop: Hide the native backdrop with dialog::backdrop { display: none; } when using the custom overlay

Constructor Props

The props that are passed when calling
new Dialog()
    export type DialogProps = {
    /**
    * If the Dialog is open.
    *
    * When passing a getter, it will be used as source of truth,
    * meaning that the value only changes when the getter returns a new value.
    *
    * Otherwise, if passing a static value, it'll serve as the default value.
    *
    * @default false
    */
    open?: MaybeGetter<boolean | undefined>;
    /**
    * Called when the value is supposed to change.
    */
    onOpenChange?: (value: boolean) => void;
    /**
    * If the dialog should close when clicking escape.
    *
    * @default true
    */
    closeOnEscape?: MaybeGetter<boolean | undefined>;
    /**
    * If the dialog should close when clicking outside.
    * Alternatively, accepts a function that receives the clicked element,
    * and returns if the dialog should close.
    *
    * @default true
    */
    closeOnOutsideClick?: MaybeGetter<boolean | undefined>;
    /**
    * If the dialog should lock the document scroll when open.
    *
    * @default true
    */
    scrollLock?: MaybeGetter<boolean | undefined>;
    };

Properties

The properties returned from
new Dialog()
  • closeOnEscape

    boolean
  • closeOnOutsideClick

    boolean
  • scrollLock

    boolean
  • refs

    {
    get: (key: "trigger" | "content" | "overlay") => HTMLElement | undefined
    attach: (key: "trigger" | "content" | "overlay") => Attachment<HTMLElement>
    key: any
    }
  • open

    boolean
  • sharedProps

    { "data-open": "" | undefined }
  • trigger

    {
    readonly "data-open": "" | undefined
    readonly "data-melt-dialog-trigger": ""
    readonly onclick: () => void
    readonly type: "button"
    }
    The trigger element.
  • content

    {
    readonly "data-open": "" | undefined
    readonly "data-melt-dialog-content": ""
    readonly onclose: () => void
    }
    The element for the dialog itself.
  • overlay

    {
    readonly "data-open": "" | undefined
    readonly "data-melt-dialog-overlay": ""
    readonly popover: "manual"
    readonly "aria-hidden": true
    }
    Optional overlay element, to replace dialog::backdrop for animation support