Dialog
Modal dialogs for confirmations, forms, and complex interactions.
Basic Dialog
A simple dialog with form elements for collecting user input.
<.dialog :let={%{hide: hide}} id="x">
<:trigger :let={attr}>
<.button variant="secondary" type="button" {attr}>
Open Dialog
</.button>
</:trigger>
<form class="space-y-4">
<.input type="text" name="name" placeholder="Name" />
<.input type="password" name="name" placeholder="Password" />
<div class="flex gap-2 justify-end">
<.button variant="secondary" type="button" phx-click={hide}>
Cancel
</.button>
<.button>
Change
</.button>
</div>
</form>
</.dialog>
Destructive Dialog
A dialog designed for destructive actions with warning styling and confirmation.
<.dialog :let={%{hide: hide}} size="sm" id="destroy">
<:trigger :let={attr}>
<.button variant="destructive" type="button" {attr}>
Destroy Server
</.button>
</:trigger>
<form class="space-y-4">
<.input type="text" name="confirm" placeholder="Enter 'destroy server' to confirm" />
<div class="flex gap-2 justify-end">
<.button variant="secondary" type="button" phx-click={hide}>
Cancel
</.button>
<.button variant="destructive">
Destroy Server
</.button>
</div>
</form>
</.dialog>
Notify Dialog
A dialog for showing notifications or status updates to the user.
<.dialog :let={%{hide: hide}} id="notify">
<:trigger :let={attr}>
<.button variant="secondary" type="button" {attr}>
Notify Me
</.button>
</:trigger>
<div class="-mt-1.5 mb-1 text-lg font-medium">Notifications</div>
<div class="mb-6 text-base text-gray-600">
You are all caught up. Good job!
</div>
<div class="flex justify-end gap-4">
<.button phx-click={hide}>
Close
</.button>
</div>
</.dialog>
Alert Dialog
An alert dialog with a destructive action, suitable for confirming critical operations.
<.dialog :let={%{hide: hide}} alert={true} id="alert-dialog">
<:trigger :let={attr}>
<.button variant="secondary" type="button" {attr}>
Alert Dialog
</.button>
</:trigger>
<div class="-mt-1.5 mb-1 text-lg font-medium">Delete Tweet</div>
<div class="mb-6 text-base text-gray-600">
Are you sure you want to delete this tweet? This action cannot be undone.
</div>
<div class="flex justify-end gap-4">
<.button phx-click={hide} variant="secondary">
Cancel
</.button>
<.button variant="destructive">
Delete Tweet
</.button>
</div>
</.dialog>
Nested Dialog
A dialog that contains another dialog, demonstrating how to handle nested modal interactions.
<.dialog :let={%{hide: hide}} alert={true} id="nested-dialog">
<:trigger :let={attr}>
<.button variant="secondary" type="button" {attr}>
Open Parent Dialog
</.button>
</:trigger>
<div class="-mt-1.5 mb-1 text-lg font-medium">Parent Dialog</div>
<div class="mb-6 text-base text-gray-600">
This dialog contains another dialog.
</div>
<div class="flex justify-end gap-4">
<.button phx-click={hide} variant="secondary">
Close
</.button>
<.dialog :let={%{hide: hide}} alert={true} id="nested-dialog-child">
<:trigger :let={attr}>
<.button variant="secondary" type="button" {attr}>
Open Child Dialog
</.button>
</:trigger>
<div class="-mt-1.5 mb-1 text-lg font-medium">Child Dialog</div>
<div class="mb-6 text-base text-gray-600">
This is a nested dialog inside the parent.
</div>
<div class="flex justify-end gap-4">
<.button phx-click={hide} variant="secondary">
Close
</.button>
<.button variant="destructive">
Action
</.button>
</div>
</.dialog>
</div>
</.dialog>
Custom Content Dialog
A dialog using the custom content slot for complete control over the dialog structure and styling.
<.dialog :let={%{hide: hide}} alert={false} id="alert-custom-content">
<:trigger :let={attr}>
<.button variant="secondary" type="button" {attr}>
Custom Content
</.button>
</:trigger>
<:content :let={{attr, %{hide: hide}}}>
<div
class={[
"not-[hidden]:animate-in [hidden]:animate-out [hidden]:fade-out-0 not-[hidden]:fade-in-0 [hidden]:zoom-out-95 not-[hidden]:zoom-in-95",
"bg-popover fixed top-[50%] left-[50%] z-50 grid w-full max-w-sm translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-sm"
]}
{attr}
>
<div class="-mt-1.5 mb-1 text-lg font-medium">Custom Content Slot</div>
<div class="mb-6 text-base text-gray-600">
Using the custom content slot to completely customize the dialog appearance.
</div>
<div class="flex justify-end gap-4">
<.button phx-click={hide} variant="secondary">
Cancel
</.button>
<.button variant="destructive">
Action
</.button>
</div>
</div>
</:content>
</.dialog>
Server Controlled with show={}
Dialog stays in DOM, visibility toggled via hidden attribute. Preserves form state and supports animations.
# Using show={@show_dialog} - Dialog stays in DOM, visibility toggled
# Preserves form state, animations work on show/hide
<.dialog id="server-dialog" show={@show_dialog} on_cancel={JS.push("close_dialog")}>
...
</.dialog>
Server Controlled with :if={}
Dialog mounted/unmounted from DOM. Form state resets on close, no exit animations.
# Using :if={@show_dialog} - Dialog mounted/unmounted from DOM
# Form state resets on close, no exit animations
<.dialog :if={@show_dialog} id="server-dialog-if" show={true} on_cancel={JS.push("close_dialog_if")}>
...
</.dialog>