Skip to content

AlertDialog

A dialog that asks before going on, HeroUI's on Kobalte's.

Solidtype_heroui.Alert_dialog is Kobalte’s Dialog as an alertdialog, with the classes HeroUI’s own alertDialogVariants gives. It is a Modal in all but these: only its own buttons close it, unless its backdrop says a press outside or Escape may; its container takes no scroll; and its icon draws HeroUI’s icon for its status.

alert_dialog_usage.mlx
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
let make () =
<Alert_dialog>
<Button variant=`danger>"Delete Project"</Button>
<Alert_dialog.Backdrop>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`danger />
<Alert_dialog.Heading>
"Delete project permanently?"
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"This will permanently delete "
<strong>"My Awesome Project"</strong>
" and all of its data. This action cannot be undone."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close variant=`danger>"Delete Project"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>
<Alert_dialog>
<Button>"Open"</Button>
<Alert_dialog.Backdrop>
<Alert_dialog.Container>
<Alert_dialog.Dialog>
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon />
<Alert_dialog.Heading>...</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>...</Alert_dialog.Body>
<Alert_dialog.Footer>...</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>
alert_dialog_statuses.mlx
module Jsx = Solidtype.Jsx
module For = Solidtype.For
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
type example = {
cancel : string;
confirm : string;
body : string;
classes : string;
header : string;
status : Solidtype_heroui.Status_icon.status;
trigger : string;
}
let examples =
[|
{
cancel = "Stay Signed In";
confirm = "Sign Out";
body =
"You'll need to sign in again to access your account. Any unsaved \
changes will be lost.";
classes = "bg-accent-soft text-accent-soft-foreground";
header = "Sign out of your account?";
status = `accent;
trigger = "Sign Out";
};
{
cancel = "Not Yet";
confirm = "Mark Complete";
body =
"This will mark the task as complete and notify all team members. The \
task will be moved to your completed list.";
classes = "bg-success-soft text-success-soft-foreground";
header = "Complete this task?";
status = `success;
trigger = "Complete Task";
};
{
cancel = "Keep Editing";
confirm = "Discard";
body =
"You have unsaved changes that will be permanently lost. Are you sure \
you want to discard them?";
classes = "bg-warning-soft text-warning-soft-foreground";
header = "Discard unsaved changes?";
status = `warning;
trigger = "Discard Changes";
};
{
cancel = "Cancel";
confirm = "Delete Account";
body =
"This will permanently delete your account and remove all your data \
from our servers. This action is irreversible.";
classes = "bg-danger-soft text-danger-soft-foreground";
header = "Delete your account?";
status = `danger;
trigger = "Delete Account";
};
|]
let make () =
<div class_="flex flex-wrap gap-4">
<For each=(fun () -> examples)>
(fun (e : example) _ ->
<Alert_dialog>
<Button class_=(fun () -> e.classes)>
(fun () -> Jsx.string e.trigger)
</Button>
<Alert_dialog.Backdrop>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=(fun () -> e.status) />
<Alert_dialog.Heading>
(fun () -> Jsx.string e.header)
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>(fun () -> Jsx.string e.body)</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>
(fun () -> Jsx.string e.cancel)
</Button>
<Button
slot=`close
variant=(fun () ->
match e.status with
| `danger -> `danger
| `default | `accent | `success | `warning ->
`primary)>
(fun () -> Jsx.string e.confirm)
</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>)
</For>
</div>
alert_dialog_placements.mlx
module Jsx = Solidtype.Jsx
module For = Solidtype.For
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
let placements =
[| (`auto, "auto"); (`top, "top"); (`center, "center"); (`bottom, "bottom") |]
let make () =
<div class_="flex flex-wrap gap-4">
<For each=(fun () -> placements)>
(fun (placement, name) _ ->
<Alert_dialog>
<Button variant=`secondary>
(fun () -> Jsx.string (String.capitalize_ascii name))
</Button>
<Alert_dialog.Backdrop>
<Alert_dialog.Container placement=(fun () -> placement)>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`accent />
<Alert_dialog.Heading>
(fun () ->
Jsx.string
(match placement with
| `auto -> "Auto Placement"
| `top | `center | `bottom ->
String.capitalize_ascii name ^ " Position"))
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
(fun () ->
Jsx.string
(match placement with
| `auto ->
"Automatically positions at the bottom on mobile \
and center on desktop for optimal user \
experience."
| `top | `center | `bottom ->
"This dialog is positioned at the " ^ name
^ " of the viewport. Critical confirmations are \
typically centered for maximum attention."))
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close>"Confirm"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>)
</For>
</div>
alert_dialog_sizes.mlx
module Jsx = Solidtype.Jsx
module For = Solidtype.For
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
let sizes =
[| (`xs, "xs"); (`sm, "sm"); (`md, "md"); (`lg, "lg"); (`cover, "cover") |]
let make () =
<div class_="flex flex-wrap gap-4">
<For each=(fun () -> sizes)>
(fun (size, name) _ ->
<Alert_dialog>
<Button variant=`secondary>
(fun () -> Jsx.string (String.capitalize_ascii name))
</Button>
<Alert_dialog.Backdrop>
<Alert_dialog.Container size=(fun () -> size)>
<Alert_dialog.Dialog>
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon class_="bg-default text-foreground">
<Gravity.Rocket class_="size-5" />
</Alert_dialog.Icon>
<Alert_dialog.Heading>
"Size: "
(fun () -> Jsx.string (String.capitalize_ascii name))
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"This alert dialog uses the "
<code>(fun () -> Jsx.string name)</code>
(fun () ->
Jsx.string
(match size with
| `cover ->
" size variant. It spans the full screen with \
margins: 16px on mobile and 40px on desktop. \
Maintains rounded corners and standard padding. \
Perfect for critical confirmations that need \
maximum width while preserving alert dialog \
aesthetics."
| `xs | `sm | `md | `lg ->
" size variant. On mobile devices, all sizes adapt \
to near full-width for optimal viewing. On \
desktop, each size provides a different maximum \
width to suit various content needs."))
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close>"Confirm"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>)
</For>
</div>

A signal is Solid’s state: each half keeps the dialog’s open state in one, where HeroUI’s uses React.useState and useOverlayState.

With a signal

Control the alert dialog using Solid's signal for simple state management. Perfect for basic use cases.

Status: closed

With a signal's setter

Use the signal's setter for a cleaner API with convenient calls like S.set set_open true, S.set set_open false, and S.update set_open not.

Status: closed

alert_dialog_controlled.mlx
module S = Solidtype.Solid
module Jsx = Solidtype.Jsx
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
(* HeroUI shows React's useState and its own useOverlayState; a signal is
Solid's state, so both halves keep the dialog's in one. *)
let make () =
let is_open, set_open = S.create_signal false in
let state_open, set_state_open = S.create_signal false in
<div class_="flex max-w-md flex-col gap-8">
<div class_="flex flex-col gap-3">
<h3 class_="text-lg font-semibold text-foreground">"With a signal"</h3>
<p class_="text-sm leading-relaxed text-pretty text-muted">
"Control the alert dialog using Solid's "
<code class_="text-foreground">"signal"</code>
" for simple state management. Perfect for basic use cases."
</p>
<div
class_="flex flex-col items-start gap-3 rounded-2xl bg-surface p-4 \
shadow-sm">
<div class_="flex w-full items-center justify-between">
<p class_="text-xs text-muted">
"Status: "
<span class_="font-mono font-medium text-foreground">
(fun () ->
Jsx.string (if S.get is_open then "open" else "closed"))
</span>
</p>
</div>
<div class_="flex gap-2">
<Button
size=`sm variant=`secondary on_click=(fun _ -> S.set set_open true)>
"Open Dialog"
</Button>
<Button
size=`sm variant=`tertiary on_click=(fun _ -> S.update set_open not)>
"Toggle"
</Button>
</div>
</div>
<Alert_dialog.Backdrop
is_open=(fun () -> S.get is_open) on_open_change=(S.set set_open)>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`accent />
<Alert_dialog.Heading>
"Controlled with a signal"
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"This alert dialog is controlled by Solid's "
<code>"signal"</code>
". Pass "
<code>"is_open"</code>
" and "
<code>"on_open_change"</code>
" props to manage the dialog state externally."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close>"Confirm"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</div>
<div class_="flex flex-col gap-3">
<h3 class_="text-lg font-semibold text-foreground">
"With a signal's setter"
</h3>
<p class_="text-sm leading-relaxed text-pretty text-muted">
"Use the "
<code class_="text-foreground">"signal"</code>
"'s setter for a cleaner API with convenient calls like "
<code>"S.set set_open true"</code>
", "
<code>"S.set set_open false"</code>
", and "
<code>"S.update set_open not"</code>
"."
</p>
<div
class_="flex flex-col items-start gap-3 rounded-2xl bg-surface p-4 \
shadow-sm">
<div class_="flex w-full items-center justify-between">
<p class_="text-xs text-muted">
"Status: "
<span class_="font-mono font-medium text-foreground">
(fun () ->
Jsx.string (if S.get state_open then "open" else "closed"))
</span>
</p>
</div>
<div class_="flex gap-2">
<Button
size=`sm
variant=`secondary
on_click=(fun _ -> S.set set_state_open true)>
"Open Dialog"
</Button>
<Button
size=`sm
variant=`tertiary
on_click=(fun _ -> S.update set_state_open not)>
"Toggle"
</Button>
</div>
</div>
<Alert_dialog.Backdrop
is_open=(fun () -> S.get state_open)
on_open_change=(S.set set_state_open)>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`success />
<Alert_dialog.Heading>
"Controlled with a signal's setter"
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"The "
<code>"signal"</code>
{js|'s setter covers the common operations. No need to manually create callbacks—just use |js}
<code>"S.set set_open true"</code>
", "
<code>"S.set set_open false"</code>
", or "
<code>"S.update set_open not"</code>
"."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close>"Confirm"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</div>
</div>
alert_dialog_custom_icon.mlx
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
let make () =
<Alert_dialog>
<Button variant=`secondary>"Reset Password"</Button>
<Alert_dialog.Backdrop>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`warning>
<Gravity.Lock_open class_="size-5" />
</Alert_dialog.Icon>
<Alert_dialog.Heading>"Reset your password?"</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"We'll send a password reset link to your email address. You'll \
need to create a new password to regain access to your account."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close>"Send Reset Link"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>
alert_dialog_custom_trigger.mlx
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
let make () =
<Alert_dialog>
<Alert_dialog.Trigger
class_="group flex items-center gap-3 rounded-2xl bg-surface p-4 \
shadow-xs select-none hover:bg-surface-secondary">
<div
class_="flex size-12 shrink-0 items-center justify-center rounded-xl \
bg-danger-soft text-danger-soft-foreground">
<Gravity.Trash_bin class_="size-6" />
</div>
<div class_="flex flex-1 flex-col gap-0.5">
<p class_="text-sm font-semibold">"Delete Item"</p>
<p class_="text-xs text-muted">"Permanently remove this item"</p>
</div>
</Alert_dialog.Trigger>
<Alert_dialog.Backdrop>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`danger>
<Gravity.Trash_bin class_="size-5" />
</Alert_dialog.Icon>
<Alert_dialog.Heading>"Delete this item?"</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"Use "
<code>"Alert_dialog.Trigger"</code>
" to create custom trigger elements beyond standard buttons. \
This example shows a card-style trigger with icons and \
descriptive text."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close variant=`danger>"Delete Item"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>
alert_dialog_backdrop_variants.mlx
module Jsx = Solidtype.Jsx
module For = Solidtype.For
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
let variants =
[| (`opaque, "opaque"); (`blur, "blur"); (`transparent, "transparent") |]
let make () =
<div class_="flex flex-wrap gap-4">
<For each=(fun () -> variants)>
(fun (variant, name) _ ->
<Alert_dialog>
<Button variant=`secondary>
(fun () -> Jsx.string (String.capitalize_ascii name))
</Button>
<Alert_dialog.Backdrop variant=(fun () -> variant)>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`accent />
<Alert_dialog.Heading>
"Backdrop: "
(fun () -> Jsx.string (String.capitalize_ascii name))
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
(fun () ->
Jsx.string
(match variant with
| `opaque ->
"An opaque dark backdrop that completely obscures \
the background, providing maximum focus on the \
dialog."
| `blur ->
"A blurred backdrop that softly obscures the \
background while maintaining visual context."
| `transparent ->
"A transparent backdrop that keeps the background \
fully visible, useful for less critical \
confirmations."))
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close>"Confirm"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>)
</For>
</div>
alert_dialog_custom_backdrop.mlx
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
let make () =
<Alert_dialog>
<Button variant=`danger>"Delete Account"</Button>
<Alert_dialog.Backdrop
class_="bg-linear-to-t from-red-950/90 via-red-950/50 to-transparent \
dark:from-red-950/95 dark:via-red-950/60"
variant=`blur>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[420px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header class_="items-center text-center">
<Alert_dialog.Icon status=`danger>
<Gravity.Triangle_exclamation class_="size-5" />
</Alert_dialog.Icon>
<Alert_dialog.Heading>
"Permanently delete your account?"
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"This action cannot be undone. All your data, settings, and \
content will be permanently removed from our servers. The \
dramatic red backdrop emphasizes the severity and \
irreversibility of this decision."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer class_="flex-col-reverse">
<Button class_="w-full" slot=`close>"Keep Account"</Button>
<Button class_="w-full" slot=`close variant=`danger>
"Delete Forever"
</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>

is_dismissable

Controls whether the alert dialog can be dismissed by clicking the overlay backdrop. Alert dialogs typically require explicit action, so this defaults to false. Set to true for less critical confirmations.

is_keyboard_dismiss_disabled

Controls whether the ESC key can dismiss the alert dialog. Alert dialogs typically require explicit action, so this defaults to true. When set to false, the ESC key will be enabled.

alert_dialog_dismiss.mlx
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
let make () =
<div class_="flex max-w-sm flex-col gap-6">
<div class_="flex flex-col gap-2">
<h3 class_="text-lg font-semibold">"is_dismissable"</h3>
<p class_="text-sm text-muted">
"Controls whether the alert dialog can be dismissed by clicking the \
overlay backdrop. Alert dialogs typically require explicit action, so \
this defaults to "
<code>"false"</code>
". Set to "
<code>"true"</code>
" for less critical confirmations."
</p>
<Alert_dialog>
<Button variant=`secondary>"Open Alert Dialog"</Button>
<Alert_dialog.Backdrop is_dismissable=false>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`danger>
<Gravity.Circle_info class_="size-5" />
</Alert_dialog.Icon>
<Alert_dialog.Heading>
"is_dismissable = false"
</Alert_dialog.Heading>
<p class_="text-sm leading-5 text-muted">
"Clicking the backdrop won't close this alert dialog"
</p>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"Try clicking outside this alert dialog on the overlay - it \
won't close. You must use the action buttons to dismiss it."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close>"Confirm"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>
</div>
<div class_="flex flex-col gap-2">
<h3 class_="text-lg font-semibold">"is_keyboard_dismiss_disabled"</h3>
<p class_="text-sm text-muted">
"Controls whether the ESC key can dismiss the alert dialog. Alert \
dialogs typically require explicit action, so this defaults to "
<code>"true"</code>
". When set to "
<code>"false"</code>
", the ESC key will be enabled."
</p>
<Alert_dialog>
<Button variant=`secondary>"Open Alert Dialog"</Button>
<Alert_dialog.Backdrop is_keyboard_dismiss_disabled=true>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`accent>
<Gravity.Circle_info class_="size-5" />
</Alert_dialog.Icon>
<Alert_dialog.Heading>
"is_keyboard_dismiss_disabled = true"
</Alert_dialog.Heading>
<p class_="text-sm leading-5 text-muted">
"ESC key is disabled"
</p>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"Press ESC - nothing happens. You must use the action \
buttons to dismiss this alert dialog."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close>"Confirm"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>
</div>
</div>

The second half closes the dialog from its own state, where HeroUI’s reads close from the dialog’s render props: the page keeps the state, which the dialog follows.

Using slot=`close

The simplest way to close a dialog. Add slot=`close to any Button component within the dialog. When clicked, it will automatically close the dialog.

Using the dialog's state

Keep the dialog's state in a signal and set it to false. This gives you full control over when and how to close the dialog, allowing you to add custom logic before closing.

alert_dialog_close_methods.mlx
module S = Solidtype.Solid
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
(* HeroUI's second dialog closes itself through its render prop's close; here
the page keeps the dialog's state, which the buttons set. *)
let make () =
let is_open, set_open = S.create_signal false in
<div class_="flex max-w-2xl flex-col gap-8">
<div class_="flex flex-col gap-2">
<h3 class_="text-lg font-semibold">"Using slot=`close"</h3>
<p class_="text-sm text-muted">
"The simplest way to close a dialog. Add "
<code>"slot=`close"</code>
" to any Button component within the dialog. When clicked, it will \
automatically close the dialog."
</p>
<Alert_dialog>
<Button variant=`secondary>"Open Dialog"</Button>
<Alert_dialog.Backdrop>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Header>
<Alert_dialog.Icon status=`accent />
<Alert_dialog.Heading>"Using slot=`close"</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"Click either button below - both have "
<code>"slot=`close"</code>
" and will close the dialog automatically."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Cancel"</Button>
<Button slot=`close>"Confirm"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>
</div>
<div class_="flex flex-col gap-2">
<h3 class_="text-lg font-semibold">"Using the dialog's state"</h3>
<p class_="text-sm text-muted">
"Keep the dialog's state in a "
<code>"signal"</code>
" and set it to "
<code>"false"</code>
". This gives you full control over when and how to close the dialog, \
allowing you to add custom logic before closing."
</p>
<Alert_dialog
is_open=(fun () -> S.get is_open) on_open_change=(S.set set_open)>
<Button variant=`secondary>"Open Dialog"</Button>
<Alert_dialog.Backdrop>
<Alert_dialog.Container>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Header>
<Alert_dialog.Icon status=`success />
<Alert_dialog.Heading>
"Using the dialog's state"
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p>
"The buttons below set the "
<code>"signal"</code>
" to "
<code>"false"</code>
". You can add validation or other logic before calling "
<code>"S.set set_open false"</code>
"."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button
variant=`tertiary on_click=(fun _ -> S.set set_open false)>
"Cancel"
</Button>
<Button on_click=(fun _ -> S.set set_open false)>
"Confirm"
</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>
</div>
</div>
alert_dialog_custom_animations.mlx
module Jsx = Solidtype.Jsx
module For = Solidtype.For
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
type animation = {
backdrop : string;
container : string;
description : string;
icon : [ `sparkles | `arrow_up_from_line ];
name : string;
}
let animations =
[|
{
backdrop =
String.concat " "
[
"data-[entering]:duration-400";
"data-[entering]:ease-[cubic-bezier(0.16,1,0.3,1)]";
"data-[exiting]:duration-200";
"data-[exiting]:ease-[cubic-bezier(0.7,0,0.84,0)]";
];
container =
String.concat " "
[
"data-[entering]:animate-in";
"data-[entering]:fade-in-0";
"data-[entering]:zoom-in-95";
"data-[entering]:duration-400";
"data-[entering]:ease-[cubic-bezier(0.16,1,0.3,1)]";
"data-[exiting]:animate-out";
"data-[exiting]:fade-out-0";
"data-[exiting]:zoom-out-95";
"data-[exiting]:duration-200";
"data-[exiting]:ease-[cubic-bezier(0.7,0,0.84,0)]";
];
description =
"Physics-based elastic scaling. Simulates a high-damping spring system \
with fast transient response and prolonged settling time. Ideal for \
Alert Dialogs and Modals.";
icon = `sparkles;
name = "Kinematic Scale";
};
{
backdrop =
String.concat " "
[
"data-[entering]:duration-500";
"data-[entering]:ease-[cubic-bezier(0.25,1,0.5,1)]";
"data-[exiting]:duration-200";
"data-[exiting]:ease-[cubic-bezier(0.5,0,0.75,0)]";
];
container =
String.concat " "
[
"data-[entering]:animate-in";
"data-[entering]:fade-in-0";
"data-[entering]:slide-in-from-bottom-4";
"data-[entering]:duration-500";
"data-[entering]:ease-[cubic-bezier(0.25,1,0.5,1)]";
"data-[exiting]:animate-out";
"data-[exiting]:fade-out-0";
"data-[exiting]:slide-out-to-bottom-2";
"data-[exiting]:duration-200";
"data-[exiting]:ease-[cubic-bezier(0.5,0,0.75,0)]";
];
description =
"Simulates movement through a medium with fluid resistance. Eliminates \
mechanical linearity for a natural, grounded feel. Perfect for Bottom \
Sheets or Toasts.";
icon = `arrow_up_from_line;
name = "Fluid Slide";
};
|]
let make () =
<div class_="flex flex-wrap gap-4">
<For each=(fun () -> animations)>
(fun (a : animation) _ ->
<Alert_dialog>
<Button variant=`secondary>(fun () -> Jsx.string a.name)</Button>
<Alert_dialog.Backdrop class_=(fun () -> a.backdrop)>
<Alert_dialog.Container class_=(fun () -> a.container)>
<Alert_dialog.Dialog class_="sm:max-w-[400px]">
<Alert_dialog.Close_trigger />
<Alert_dialog.Header>
<Alert_dialog.Icon status=`accent>
(fun () ->
match a.icon with
| `sparkles ->
Jsx.element <Gravity.Sparkles class_="size-5" />
| `arrow_up_from_line ->
Jsx.element
<Gravity.Arrow_up_from_line class_="size-5" />)
</Alert_dialog.Icon>
<Alert_dialog.Heading>
(fun () -> Jsx.string a.name) " Animation"
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body>
<p class_="mt-1">(fun () -> Jsx.string a.description)</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Close"</Button>
<Button slot=`close>"Try Again"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>)
</For>
</div>

HeroUI’s Custom Portal example gives the backdrop React Aria’s UNSTABLE_portalContainer, which the port does not take yet: a dialog is drawn at the end of the page.

class_ is added after HeroUI’s classes.

alert_dialog_tailwind.mlx
module Button = Solidtype_heroui.Button
module Alert_dialog = Solidtype_heroui.Alert_dialog
let make () =
<Alert_dialog>
<Button variant=`secondary>"Sign out"</Button>
<Alert_dialog.Backdrop
class_="bg-overlay/50 dark:bg-overlay/60" variant=`blur>
<Alert_dialog.Container>
<Alert_dialog.Dialog
class_="relative overflow-hidden border border-border/80 bg-surface \
shadow-2xl ring-1 ring-accent/10 sm:max-w-[400px] \
dark:border-border/90 dark:bg-surface dark:ring-accent/15">
<div
aria_hidden=true
class_="pointer-events-none absolute inset-x-0 top-0 h-24 \
bg-linear-to-b from-accent/6 to-transparent \
dark:from-accent/10"
/>
<div
aria_hidden=true
class_="pointer-events-none absolute inset-x-8 top-0 h-px \
bg-linear-to-r from-transparent via-accent/35 \
to-transparent dark:via-accent/45"
/>
<Alert_dialog.Header class_="relative">
<Alert_dialog.Icon status=`accent />
<Alert_dialog.Heading>
"Sign out of your account?"
</Alert_dialog.Heading>
</Alert_dialog.Header>
<Alert_dialog.Body class_="relative">
<p class_="text-muted">
"You will be signed out on this device. Unsaved work in "
<strong class_="text-foreground">"Acme Workspace"</strong>
" may be lost unless it was saved to the cloud."
</p>
</Alert_dialog.Body>
<Alert_dialog.Footer>
<Button slot=`close variant=`tertiary>"Stay signed in"</Button>
<Button slot=`close>"Sign out"</Button>
</Alert_dialog.Footer>
</Alert_dialog.Dialog>
</Alert_dialog.Container>
</Alert_dialog.Backdrop>
</Alert_dialog>

HeroUI’s classes are global, so a stylesheet restyles every one, as with HeroUI in React:

@layer components {
.alert-dialog__dialog {
@apply rounded-2xl;
}
.alert-dialog__heading {
@apply text-lg font-semibold;
}
}
  • .alert-dialog__trigger, .alert-dialog__backdrop, .alert-dialog__container, .alert-dialog__dialog, .alert-dialog__header, .alert-dialog__heading, .alert-dialog__icon, .alert-dialog__body, .alert-dialog__footer, .alert-dialog__close-trigger
  • .alert-dialog__backdrop--opaque, --blur, --transparent
  • .alert-dialog__dialog--xs, --sm, --md, --lg, --cover
  • .alert-dialog__icon--default, --accent, --success, --warning, --danger
  • Entering: [data-entering="true"] on the backdrop and the container
  • Exiting: [data-exiting="true"] on the backdrop and the container
  • Placement: [data-placement="auto"], and the others, on the container and the dialog

It shares Modal’s making, on Kobalte’s dialog: see Modal. Its dialog’s role is alertdialog, as React Aria’s is, and a reader’s dismiss button is in it only while its backdrop may be dismissed.

Each prop beside the name HeroUI’s React component gives it.

React solidtype Type Default Description
isOpen is_open bool Whether it is open, controlled
defaultOpen default_open bool false Whether it starts open
onOpenChange on_open_change bool -> unit Told as it opens or closes
React solidtype Type Default Description
variant variant `opaque | `blur | `transparent `opaque Its look
isDismissable is_dismissable bool false Whether a press on it closes the dialog
isKeyboardDismissDisabled is_keyboard_dismiss_disabled bool true Whether Escape does not
isOpen is_open bool With no Alert_dialog around it, whether it is open
onOpenChange on_open_change bool -> unit With no Alert_dialog around it, told as it opens or closes
className class_ string Added after HeroUI’s classes
React solidtype Type Default Description
placement placement `auto | `center | `top | `bottom `auto Where the dialog is
size size `xs | `sm | `md | `lg | `cover `md Its width
className class_ string Added after HeroUI’s classes
React solidtype Type Default Description
status status `default | `accent | `success | `warning | `danger `danger Its colour and icon
className class_ string Added after HeroUI’s classes
children children elements An icon of its own
Section titled “AlertDialog.Dialog, Header, Body, Footer, Heading, CloseTrigger, Trigger”

As Modal’s.

Original HeroUI documentation: AlertDialog.

The same HeroUI AlertDialog twice, under the same props: in solidtype on the left, in React on the right. Below them, every attribute of each trigger: a marked row is one they disagree on, and a dimmed row is a framework’s own, which no style reads.

solidtype — OCaml, on Solid and Kobalte
React — TypeScript, on React Aria
attributesolidtypeReact