Documentation
Overlays Dialog

Dialog

Modal dialogs for confirmations, forms, and complex interactions.

Interactive Demo

Basic Dialog

Dialog Sizes

Alert Dialog

The Dialog component provides accessible modal dialogs built on the native <dialog> element. It supports server-controlled visibility, multiple sizes, alert dialogs, and custom content with backdrop handling.

Import

use PUI
# or
import PUI.Dialog

Basic Usage

Dialogs require an id and can be shown/hidden programmatically:

<.button phx-click={PUI.Dialog.show_dialog("my-dialog")}>
Open Dialog
</.button>
<.dialog id="my-dialog">
<:content>
<h2 class="text-lg font-semibold">Dialog Title</h2>
<p class="mt-2 text-muted-foreground">
This is the dialog content.
</p>
<div class="mt-4 flex justify-end gap-2">
<.button variant="outline"
phx-click={PUI.Dialog.hide_dialog("my-dialog")}>
Cancel
</.button>
<.button>Confirm</.button>
</div>
</:content>
</.dialog>

Server-Controlled

Control dialog visibility from the server with the show attribute:

<.dialog id="server-dialog" show={@show_dialog}>
<:content>
<p>This dialog is controlled by server state.</p>
</:content>
</.dialog>
def handle_event("open", _, socket) do
{:noreply, assign(socket, show_dialog: true)}
end

Sizes

Dialogs come in four sizes:

<.dialog id="sm-dialog" size="sm">...</.dialog>
<.dialog id="md-dialog" size="md">...</.dialog> <!-- default -->
<.dialog id="lg-dialog" size="lg">...</.dialog>
<.dialog id="xl-dialog" size="xl">...</.dialog>

Alert Dialog

Alert dialogs require explicit user action and cannot be dismissed by clicking the backdrop:

<.dialog id="alert-dialog" alert={true}>
<:content>
<h2 class="text-lg font-semibold text-destructive">
Delete Account?
</h2>
<p class="mt-2">This action cannot be undone.</p>
<div class="mt-4 flex justify-end gap-2">
<.button variant="outline"
phx-click={PUI.Dialog.hide_dialog("alert-dialog")}>
Cancel
</.button>
<.button variant="destructive" phx-click="delete_account">
Delete
</.button>
</div>
</:content>
</.dialog>

With Trigger Slot

Use the trigger slot for inline trigger buttons:

<.dialog id="trigger-dialog">
<:trigger>
<.button>Open</.button>
</:trigger>
<:content>
<p>Dialog with trigger slot.</p>
</:content>
</.dialog>

Unstyled / Headless

<.dialog id="headless" variant="unstyled">
<:content>
<div class="my-custom-dialog-panel">
Custom styled dialog content
</div>
</:content>
</.dialog>

API Reference

Attributes

Name Type Default Description
id string required Unique identifier for the dialog
show boolean false Server-controlled visibility
alert boolean false Alert dialog mode (no backdrop dismiss)
size string "md" Dialog size: "sm", "md", "lg", "xl"
on_cancel JS %JS{} JS command to run on cancel
variant string "default" "default" or "unstyled"
class string "" Additional CSS classes

Slots

Name Required Description
trigger Inline trigger element
content Dialog content
inner_block Alternative to named slots