Components

Dialog

A window overlaid on the primary window, rendering the content underneath inert.

php artisan blatui:add dialog
<x-ui.dialog>
    <x-ui.dialog-trigger>
        <x-ui.button variant="outline">Edit Profile</x-ui.button>
    </x-ui.dialog-trigger>
    <x-ui.dialog-content class="sm:max-w-[425px]">
        <x-ui.dialog-header>
            <x-ui.dialog-title>Edit profile</x-ui.dialog-title>
            <x-ui.dialog-description>
                Make changes to your profile here. Click save when you're done.
            </x-ui.dialog-description>
        </x-ui.dialog-header>
        <div class="grid gap-4 py-2">
            <div class="grid gap-2">
                <x-ui.label for="name">Name</x-ui.label>
                <x-ui.input id="name" value="Pedro Duarte" />
            </div>
            <div class="grid gap-2">
                <x-ui.label for="username">Username</x-ui.label>
                <x-ui.input id="username" value="@peduarte" />
            </div>
        </div>
        <x-ui.dialog-footer>
            <x-ui.button type="submit">Save changes</x-ui.button>
        </x-ui.dialog-footer>
    </x-ui.dialog-content>
</x-ui.dialog>

Confirmation

<x-ui.dialog>
    <x-ui.dialog-trigger>
        <x-ui.button variant="outline">Delete account</x-ui.button>
    </x-ui.dialog-trigger>
    <x-ui.dialog-content class="sm:max-w-[425px]">
        <x-ui.dialog-header>
            <x-ui.dialog-title>Are you absolutely sure?</x-ui.dialog-title>
            <x-ui.dialog-description>
                This action cannot be undone. This will permanently delete your account and remove your data from our servers.
            </x-ui.dialog-description>
        </x-ui.dialog-header>
        <x-ui.dialog-footer>
            <x-ui.dialog-close>
                <x-ui.button variant="outline">Cancel</x-ui.button>
            </x-ui.dialog-close>
            <x-ui.button variant="destructive">Delete account</x-ui.button>
        </x-ui.dialog-footer>
    </x-ui.dialog-content>
</x-ui.dialog>

Dispatchable

Alice Martin
Bob Dupont
Carol Nguyen
{{-- Dispatchable mode (id="..."). The "Remove" trigger lives inside a @foreach, but there
     is ONE shared dialog defined once below — no per-row modal markup, no scope coupling.
     The trigger opens it from anywhere with $dispatch('open-dialog-{id}'); pass row context
     in the event detail and capture it on dialog-content. Close from anywhere with
     $dispatch('close-dialog-{id}'). --}}
<div class="w-full max-w-sm space-y-2">
    @foreach (['Alice Martin', 'Bob Dupont', 'Carol Nguyen'] as $member)
        <div class="flex items-center justify-between rounded-md border px-3 py-2 text-sm">
            <span>{{ $member }}</span>
            <x-ui.button
                variant="outline"
                size="sm"
                x-data
                data-name="{{ $member }}"
                x-on:click="$dispatch('open-dialog-member', { name: $el.dataset.name })"
            >Remove</x-ui.button>
        </div>
    @endforeach

    {{-- Defined once — shared by every row above. --}}
    <x-ui.dialog id="member">
        <x-ui.dialog-content x-data="{ name: '' }" @open-dialog-member.window="name = $event.detail?.name || ''">
            <x-ui.dialog-header>
                <x-ui.dialog-title>Remove member</x-ui.dialog-title>
                <x-ui.dialog-description>
                    Remove <span class="text-foreground font-medium" x-text="name"></span> from the team? This can't be undone.
                </x-ui.dialog-description>
            </x-ui.dialog-header>
            <x-ui.dialog-footer>
                <x-ui.button variant="outline" x-on:click="$dispatch('close-dialog-member')">Cancel</x-ui.button>
                <x-ui.button variant="destructive" x-on:click="$dispatch('close-dialog-member')">Remove</x-ui.button>
            </x-ui.dialog-footer>
        </x-ui.dialog-content>
    </x-ui.dialog>
</div>

Feedback

<x-ui.dialog>
    <x-ui.dialog-trigger>
        <x-ui.button variant="outline"><x-lucide-message-square aria-hidden="true" /> Submit feedback</x-ui.button>
    </x-ui.dialog-trigger>
    <x-ui.dialog-content class="sm:max-w-[425px]">
        <x-ui.dialog-header>
            <x-ui.dialog-title>Submit feedback</x-ui.dialog-title>
            <x-ui.dialog-description>Tell us what's working well or what could be better.</x-ui.dialog-description>
        </x-ui.dialog-header>
        <div class="flex flex-col gap-4 py-2">
            <x-ui.field>
                <x-ui.field-label for="fb-title">Title</x-ui.field-label>
                <x-ui.input id="fb-title" placeholder="Short summary" />
            </x-ui.field>
            <x-ui.field>
                <x-ui.field-label for="fb-type">Type</x-ui.field-label>
                <x-ui.select>
                    <x-ui.select-trigger id="fb-type" class="w-full"><x-ui.select-value placeholder="Select a type" /></x-ui.select-trigger>
                    <x-ui.select-content>
                        <x-ui.select-item value="bug">Bug report</x-ui.select-item>
                        <x-ui.select-item value="idea">Idea</x-ui.select-item>
                        <x-ui.select-item value="question">Question</x-ui.select-item>
                        <x-ui.select-item value="other">Other</x-ui.select-item>
                    </x-ui.select-content>
                </x-ui.select>
            </x-ui.field>
            <x-ui.field>
                <x-ui.field-label for="fb-desc">Description</x-ui.field-label>
                <x-ui.textarea id="fb-desc" placeholder="Describe it in a little more detail…" />
            </x-ui.field>
        </div>
        <x-ui.dialog-footer>
            <x-ui.dialog-close>
                <x-ui.button variant="outline">Cancel</x-ui.button>
            </x-ui.dialog-close>
            <x-ui.button>Send feedback</x-ui.button>
        </x-ui.dialog-footer>
    </x-ui.dialog-content>
</x-ui.dialog>

Fullscreen

{{-- Pass `fullscreen` to dialog-content for an edge-to-edge takeover (mobile, editors, viewers). --}}
<x-ui.dialog>
    <x-ui.dialog-trigger>
        <x-ui.button variant="outline">Open full-screen</x-ui.button>
    </x-ui.dialog-trigger>
    <x-ui.dialog-content fullscreen>
        <div class="mx-auto flex w-full max-w-2xl flex-1 flex-col gap-6">
            <x-ui.dialog-header>
                <x-ui.dialog-title>Full-screen dialog</x-ui.dialog-title>
                <x-ui.dialog-description>
                    An edge-to-edge takeover — ideal on mobile, or for focused editing and media.
                </x-ui.dialog-description>
            </x-ui.dialog-header>

            <div class="flex-1 space-y-4">
                <div class="grid gap-2">
                    <x-ui.label for="fs-title">Title</x-ui.label>
                    <x-ui.input id="fs-title" placeholder="Untitled document" />
                </div>
                <div class="grid gap-2">
                    <x-ui.label for="fs-body">Body</x-ui.label>
                    <x-ui.textarea id="fs-body" rows="6" placeholder="Write something…" />
                </div>
            </div>

            <x-ui.dialog-footer>
                <x-ui.button variant="outline" @click="open = false">Cancel</x-ui.button>
                <x-ui.button @click="open = false">Save</x-ui.button>
            </x-ui.dialog-footer>
        </div>
    </x-ui.dialog-content>
</x-ui.dialog>

Positioned

{{-- Dialogs anchored to different edges/corners via the `position` prop. --}}
<div class="flex flex-wrap items-center gap-2">
    @foreach (['top-left' => 'Top left', 'top' => 'Top', 'top-right' => 'Top right', 'center' => 'Center', 'bottom-left' => 'Bottom left', 'bottom' => 'Bottom', 'bottom-right' => 'Bottom right'] as $pos => $label)
        <x-ui.dialog>
            <x-ui.dialog-trigger>
                <x-ui.button variant="outline" size="sm">{{ $label }}</x-ui.button>
            </x-ui.dialog-trigger>
            <x-ui.dialog-content position="{{ $pos }}" class="sm:max-w-sm">
                <x-ui.dialog-header>
                    <x-ui.dialog-title>{{ $label }}</x-ui.dialog-title>
                    <x-ui.dialog-description>This dialog is anchored to the <strong>{{ $label }}</strong> of the screen.</x-ui.dialog-description>
                </x-ui.dialog-header>
                <x-ui.dialog-footer>
                    <x-ui.button @click="open = false">Got it</x-ui.button>
                </x-ui.dialog-footer>
            </x-ui.dialog-content>
        </x-ui.dialog>
    @endforeach
</div>

Scroll

<x-ui.dialog>
    <x-ui.dialog-trigger>
        <x-ui.button variant="outline">View terms</x-ui.button>
    </x-ui.dialog-trigger>
    <x-ui.dialog-content class="sm:max-w-[480px]">
        <x-ui.dialog-header>
            <x-ui.dialog-title>Terms of Service</x-ui.dialog-title>
            <x-ui.dialog-description>Please review our terms before continuing.</x-ui.dialog-description>
        </x-ui.dialog-header>
        <div class="text-muted-foreground flex max-h-[50vh] flex-col gap-3 overflow-y-auto pr-2 text-sm">
            <p>By accessing this service you agree to be bound by these terms and all applicable laws and regulations.</p>
            <p>You may not use the materials for any commercial purpose without prior written consent.</p>
            <p>The materials are provided on an "as is" basis without warranties of any kind, either express or implied.</p>
            <p>In no event shall we be liable for any damages arising out of the use or inability to use the materials.</p>
            <p>We may revise these terms at any time without notice. By using this service you agree to be bound by the current version.</p>
            <p>These terms are governed by and construed in accordance with applicable law.</p>
        </div>
        <x-ui.dialog-footer>
            <x-ui.dialog-close>
                <x-ui.button variant="outline">Decline</x-ui.button>
            </x-ui.dialog-close>
            <x-ui.button>Accept</x-ui.button>
        </x-ui.dialog-footer>
    </x-ui.dialog-content>
</x-ui.dialog>

API Reference

Props, slots and exposed methods for <x-ui.dialog>.

Props

Prop Type Default Description
open bool false Initial open state of the dialog on first render.
id string Enables "dispatchable" mode: the dialog also opens/closes from anywhere via $dispatch('open-dialog-{id}') / $dispatch('close-dialog-{id}'). Lets a trigger inside a loop or partial drive a single shared modal defined elsewhere (pair with <x-ui.dialog-trigger for="{id}">).
showClose bool true Set on <x-ui.dialog-content>. Render the built-in top-right close (X) button.
fullscreen bool false Set on <x-ui.dialog-content>. Render the dialog edge-to-edge (inset-0) instead of a centered box — useful for mobile-style takeovers, editors, and media viewers.
position string 'center' Set on <x-ui.dialog-content>. Where the box sits within the viewport.
center top bottom left right top-left top-right bottom-left bottom-right
for string Set on <x-ui.dialog-trigger>. Opens a dispatchable dialog defined elsewhere (matching its id) instead of one in the same scope.

Slots

Slot Description
default Holds the <x-ui.dialog-trigger> and <x-ui.dialog-content>. The root only manages open state.
trigger The clickable element that opens the dialog, wrapped in <x-ui.dialog-trigger>.
content The modal panel (<x-ui.dialog-content>), teleported to <body>. Compose it from <x-ui.dialog-header> (with <x-ui.dialog-title> + <x-ui.dialog-description>), your body, and <x-ui.dialog-footer>.
close Wrap any element in <x-ui.dialog-close> to make it dismiss the dialog (in addition to the built-in X, Escape, and overlay click).