Skip to content

Dialog

A dialog is a modal window displayed on top of the current page.

---
---
<div x-cloak x-data x-dialog>
<button x-dialog:trigger> <i class="i-lucide-download w-4 h-4"></i> Download</button>
<template x-teleport="body">
<div data-scope="dialog" data-part="container">
<div x-dialog:backdrop></div>
<div x-dialog:positioner>
<div x-dialog:content>
<header>
<h2 x-dialog:title>Confirm Download</h2>
</header>
<div x-dialog:description>
The file <code>exports.zip</code> will be saved to your disk.
</div>
<footer>
<button
type="button"
data-scope="dialog"
data-part="cancel-trigger"
x-on:click="$dialog.setOpen(false)"
>
Cancel
</button>
<button
type="button"
data-scope="dialog"
data-part="confirm-trigger"
x-on:click="$dialog.setOpen(false)"
>
Download
</button>
</footer>
<button type="button" x-dialog:close-trigger>
<i class="i-lucide-x w-4 h-4"></i>
</button>
</div>
</div>
</div>
</template>
</div>
<style>
[data-part="root"] {
@apply contents;
}
[data-part="trigger"] {
@apply inline-flex justify-center items-center gap-2 px-2.5 py-1 min-h-9 rounded border text-sm font-medium bg-white text-zinc-700 hover:bg-zinc-100 border-zinc-300/60 cursor-pointer;
}
[data-part="container"] {
@apply contents;
}
[data-part="backdrop"] {
@apply fixed inset-0 bg-zinc-900/40 backdrop-blur-sm z-[1300];
}
[data-part="positioner"] {
@apply fixed inset-0 flex justify-center items-center z-[1400];
}
[data-part="content"] {
@apply relative max-w-80 md:max-w-lg bg-white border border-zinc-300/60 rounded-md shadow-sm;
}
[data-part="content"] > header {
@apply border-b border-zinc-200/60 px-4 py-2;
}
[data-part="content"] > footer {
@apply border-t border-zinc-200/60 px-4 py-2 flex justify-between gap-4;
}
[data-part="title"] {
@apply text-lg text-zinc-600 font-semibold;
}
[data-part="description"] {
@apply p-4 text-zinc-600 text-sm;
}
[data-part="description"] > code {
@apply text-zinc-900;
}
[data-part="close-trigger"] {
@apply absolute p-1 h-6 w-6 inline-flex justify-center items-center top-2 right-2 bg-transparent hover:bg-zinc-100 text-zinc-500 rounded-md cursor-pointer;
}
[data-part="cancel-trigger"] {
@apply inline-flex justify-center items-center gap-2 px-2.5 py-1 w-full min-h-9 rounded border text-sm font-medium bg-white text-zinc-700 hover:bg-zinc-100 border-zinc-300/60 cursor-pointer;
}
[data-part="confirm-trigger"] {
@apply inline-flex justify-center items-center gap-2 px-2.5 py-1 w-full min-h-9 rounded text-sm font-medium bg-zinc-700 text-white hover:bg-zinc-600 cursor-pointer;
}
@keyframes enter {
from {
opacity: 0;
transform: scale(0.95) translateY(-10px);
}
to {
opacity: 1;
transform: scale(1) translateY(0);
}
}
@keyframes exit {
from {
opacity: 1;
transform: scale(1) translateY(0);
}
to {
opacity: 0;
transform: scale(0.95) translateY(-10px);
}
}
[data-part="content"][data-state="open"] {
animation: enter 0.2s ease-out;
}
[data-part="content"][data-state="closed"] {
animation: exit 0.2s ease-out;
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
[data-part="backdrop"][data-state="open"] {
animation: fade-in 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
[data-part="backdrop"][data-state="closed"] {
animation: fade-out 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}
</style>