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.
Under the Hood
This component uses an Alpine.js component (x-data="rzDialog") to manage its state and interactions. It utilizes <template x-teleport="body"> to ensure the dialog is rendered at the end of the document body, avoiding potential z-index issues.
Basic Dialog
This example shows a standard dialog. The DialogTrigger component wraps a button that, when clicked, opens the DialogContent.
Basic Dialog Example
This is the content of the basic dialog. You can close it using the 'X' button, pressing Escape, or clicking the backdrop.
This is the main body content.
<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.
This dialog has no header and the default close button is hidden.
Important Information
This dialog uses custom markup inside the DialogTitle.
<!-- 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.
HTMX Loaded Content
Loading content...
<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!;
}@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.
Static Documentation Limitation
This specific "Close via HTMX Header" example requires server-side processing to send the `HX-Trigger` response header. Since this documentation is rendered as static HTML, clicking the "Submit & Close" button below will not actually close the dialog in this demo environment. It demonstrates the client-side setup and the expected server-side response.
Close via HTMX Header
<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>[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>");
}