RizzyUI

Dialog

The RzDialog component suite provides a flexible way to display modal dialogs. It's a composable system built from components like DialogTrigger, DialogContent, DialogHeader, and more. It leverages Alpine.js for client-side state management, transitions, focus trapping, and standard closing mechanisms. Its internal body and footer areas have stable IDs, allowing HTMX to dynamically load or update content within the dialog after it's opened.

Basic Dialog

This example shows a standard dialog. The DialogTrigger component wraps a button that, when clicked, opens the DialogContent.

Source
<RzDialog>
    <DialogTrigger AsChild>
        <RzButton Variant="ThemeVariant.Primary">Open Basic Dialog</RzButton>
    </DialogTrigger>
    <DialogContent>
        <DialogHeader>
            <DialogTitle>Basic Dialog Example</DialogTitle>
            <DialogDescription>
                This is the content of the basic dialog. You can close it using the 'X' button, pressing Escape, or clicking the backdrop.
            </DialogDescription>
        </DialogHeader>
        <div class="p-6">
            <p>This is the main body content.</p>
        </div>
        <DialogFooter>
            <DialogClose AsChild>
                <RzButton Variant="ThemeVariant.Accent">Close</RzButton>
            </DialogClose>
            <RzButton Variant="ThemeVariant.Primary">Okay</RzButton>
        </DialogFooter>
    </DialogContent>
</RzDialog>

Customizing Appearance

You can customize the dialog's appearance using parameters like Size on DialogContent, or by omitting components like DialogHeader.

Source
<!-- Small Dialog without Header -->
<RzDialog>
    <DialogTrigger AsChild>
        <RzButton>Open Small (No Header)</RzButton>
    </DialogTrigger>
    <DialogContent Size="ModalSize.Small" ShowCloseButton="false">
        <div class="p-6">
            <p>This dialog has no header and the default close button is hidden.</p>
            <div class="mt-4 text-right">
                <DialogClose AsChild>
                    <RzButton Variant="ThemeVariant.Accent">Close Me</RzButton>
                </DialogClose>
            </div>
        </div>
    </DialogContent>
</RzDialog>

<!-- Dialog with Custom TitleContent -->
<RzDialog>
    <DialogTrigger AsChild>
        <RzButton>Open Custom Title</RzButton>
    </DialogTrigger>
    <DialogContent Size="ModalSize.Medium">
        <DialogHeader>
            <DialogTitle>
                <div class="flex items-center gap-2 font-semibold text-primary">
                    <Blazicon Svg="MdiIcon.Information" class="size-5"/>
                    <span>Important Information</span>
                </div>
            </DialogTitle>
        </DialogHeader>
        <div class="p-6">
            <p>This dialog uses custom markup inside the <code>DialogTitle</code>.</p>
        </div>
    </DialogContent>
</RzDialog>

HTMX Content Loading

This demonstrates using HTMX to load content dynamically into the dialog's body. The DialogTrigger opens the dialog, and its child RzButton has HTMX attributes to fetch content, targeting the dialog's specific BodyId.

Blazor Component
<RzDialog @ref="htmxLoadDialogRef">
    <DialogTrigger AsChild>
        <RzButton hx-get="/demo/htmx-dialog-sample"
                  hx-target="@($"#{htmxLoadDialogRef.BodyId}")"
                  hx-swap="innerHTML"
                  hx-indicator="@($"#{htmxLoadDialogRef.BodyId}-spinner")">
            Open & Load Content via HTMX
        </RzButton>
    </DialogTrigger>
    <DialogContent>
        <DialogHeader>
            <DialogTitle>HTMX Loaded Content</DialogTitle>
        </DialogHeader>
        <div id="@htmxLoadDialogRef.BodyId" class="p-6">
            <div class="text-center p-4">
                <RzSpinner Id="@($"#{htmxLoadDialogRef.BodyId}-spinner")" Size="Size.Large"/>
                <p class="mt-2">Loading content...</p>
            </div>
        </div>
    </DialogContent>
</RzDialog>

@code {
    RzDialog htmxLoadDialogRef = default!;
}
Demo Content Page (/demo/htmx-dialog-sample)
@page "/demo/htmx-dialog-sample"
@layout RizzyUI.Docs.Components.Layout.EmptyLayout
@using RizzyUI

<p>This content was loaded dynamically via an HTMX request!</p>
<RzAlert Variant="ThemeVariant.Success">
    <AlertTitle>Success</AlertTitle>
    <AlertDescription>Content loaded successfully.</AlertDescription>
</RzAlert>

Closing with HTMX

Dialogs can be closed from the server by returning an HTMX response header that triggers the event specified in the `CloseEventName` parameter (default: `rz:modal-close`). This example shows a form inside the dialog; upon successful submission, the server sends back the trigger header.

Blazor Component
<RzDialog>
    <DialogTrigger AsChild>
        <RzButton>Open HTMX Close Example</RzButton>
    </DialogTrigger>
    <DialogContent>
        <DialogHeader>
            <DialogTitle>Close via HTMX Header</DialogTitle>
        </DialogHeader>
        <div class="p-6">
            <form hx-post="/api/dialog/htmx-close-action"
                  hx-target="this"
                  hx-swap="outerHTML">
                <p>Submit this form. The server response will include an HX-Trigger header to close this dialog.</p>
                <div class="text-right mt-4">
                    <RzButton type="submit" Variant="ThemeVariant.Success">Submit & Close</RzButton>
                </div>
            </form>
        </div>
    </DialogContent>
</RzDialog>
Example Controller Action (using RzController)
[HttpPost("/api/dialog/htmx-close-action")]
public IResult CloseDialogAction()
{
    // Process form data if needed...

    // Add the HX-Trigger header to close the dialog
    HttpContext.Response.Htmx(h => h.Trigger(RizzyUI.Constants.Events.ModalClose));

    // Can return swapped content for the form, or just Ok/NoContent if only closing
    return Ok("<p>Form Submitted! Dialog closed by server.</p>"); 
}