Alert Dialog
A modal for critical confirmations.
use herogpui::components::alert_dialog::{AlertDialog, AlertDialogCloseTrigger};AlertDialog on docs.rsSource at v0.14.0
Usage
Showing Usage, live: HeroGPUI compiled to WebAssembly. The canvas has no accessibility tree; each example's description and code below carry the same information.
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Button, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
let is_open = self.alert_dialog_open;
{
overlay_min_h(
gpui::div()
.relative()
.flex()
.flex_col()
.items_center()
.w_full(),
is_open,
240.,
)
.child(
Button::new("alert-dialog-open")
.label("Delete project")
.variant(Variant::Danger)
.on_press(cx.listener(|this, _, _, cx| {
this.alert_dialog_open = true;
cx.notify();
})),
)
.child(
AlertDialog::new("Delete this project?").id("alert-dialog")
.description(
"This removes the project and every deployment. \
This action cannot be undone.",
)
.is_open(is_open)
// The panel's entry zoom interpolates the same
// value the panel paints.
.radius(px(12.))
.child(AlertDialogCloseTrigger::new())
.footer_child(
Button::new("alert-dialog")
.label("Cancel")
.variant(Variant::Tertiary)
.on_press(cx.listener(|this, _, _, cx| {
this.alert_dialog_open = false;
cx.notify();
})),
)
.footer_child(
Button::new("alert-dialog")
.label("Delete")
.variant(Variant::Danger)
.on_press(cx.listener(|this, _, _, cx| {
this.alert_dialog_open = false;
cx.notify();
})),
)
.on_open_change(cx.listener(|this, v: &bool, _, cx| {
this.alert_dialog_open = *v;
cx.notify();
})),
)
.into_any_element()
}Also calls overlay_min_h (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, AlertDialogSize, Button, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w_full()
.gap(px(12.))
.children([
("ad-size-xs", "Xs", AlertDialogSize::Xs),
("ad-size-sm", "Sm", AlertDialogSize::Sm),
("ad-size-md", "Md", AlertDialogSize::Md),
("ad-size-lg", "Lg", AlertDialogSize::Lg),
("ad-size-cover", "Cover", AlertDialogSize::Cover),
]
.into_iter()
.map(|(key, label, size)| {
let open = self.demo_overlay(key);
overlay_demo(
open,
key,
label,
AlertDialog::new(format!("Size: {label}")).id(key)
.description("Every size shares one panel style.")
.is_open(open)
.size(size)
.child(AlertDialogCloseTrigger::new())
.on_open_change(cx.listener(
move |this, v: &bool, _, cx| {
this.set_demo_flag(key, *v);
cx.notify();
},
))
.into_any_element(),
cx,
)
}))Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Button, Color, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w_full()
.gap(px(12.))
.children([
("ad-st-default", "Default", Color::Default),
("ad-st-accent", "Accent", Color::Accent),
("ad-st-success", "Success", Color::Success),
("ad-st-warning", "Warning", Color::Warning),
("ad-st-danger", "Danger", Color::Danger),
]
.into_iter()
.map(|(key, label, status)| {
let open = self.demo_overlay(key);
overlay_demo(
open,
key,
label,
AlertDialog::new(format!("{label} status")).id(key)
.description("The status colours the icon above the title.")
.is_open(open)
.status(status)
.child(AlertDialogCloseTrigger::new())
.on_open_change(cx.listener(
move |this, v: &bool, _, cx| {
this.set_demo_flag(key, *v);
cx.notify();
},
))
.into_any_element(),
cx,
)
}))Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Button, ModalPlacement, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w_full()
.gap(px(12.))
.children([
("ad-pl-auto", "Auto", ModalPlacement::Auto),
("ad-pl-center", "Center", ModalPlacement::Center),
("ad-pl-top", "Top", ModalPlacement::Top),
("ad-pl-bottom", "Bottom", ModalPlacement::Bottom),
]
.into_iter()
.map(|(key, label, placement)| {
let open = self.demo_overlay(key);
overlay_demo(
open,
key,
label,
AlertDialog::new(format!("Placement: {label}")).id(key)
.description("The panel keeps its own size.")
.is_open(open)
.placement(placement)
.child(AlertDialogCloseTrigger::new())
.on_open_change(cx.listener(
move |this, v: &bool, _, cx| {
this.set_demo_flag(key, *v);
cx.notify();
},
))
.into_any_element(),
cx,
)
}))Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Backdrop, Button, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w_full()
.gap(px(12.))
.children(herogpui::core::Backdrop::ALL
.iter()
.map(|backdrop| {
let key: &'static str = match backdrop {
herogpui::core::Backdrop::Opaque => "ad-bd-opaque",
herogpui::core::Backdrop::Blur => "ad-bd-blur",
herogpui::core::Backdrop::Transparent => "ad-bd-transparent",
};
let open = self.demo_overlay(key);
overlay_demo(
open,
key,
backdrop.label(),
AlertDialog::new(format!("Backdrop: {}", backdrop.label())).id(key)
.description("The scrim behind the panel.")
.is_open(open)
.backdrop(*backdrop)
.child(AlertDialogCloseTrigger::new())
.on_open_change(cx.listener(
move |this, v: &bool, _, cx| {
this.set_demo_flag(key, *v);
cx.notify();
},
))
.into_any_element(),
cx,
)
}))Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Button, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
overlay_demo(
self.demo_overlay("ad-controlled"),
"ad-controlled",
"Open (controlled)",
AlertDialog::new("Controlled").id("alert-dialog-controlled")
.description("The flag lives with the caller; closing reports through onOpenChange.")
.is_open(self.demo_overlay("ad-controlled"))
.child(AlertDialogCloseTrigger::new())
.on_open_change(cx.listener(|this, v: &bool, _, cx| {
this.set_demo_flag("ad-controlled", *v);
cx.notify();
}))
.into_any_element(),
cx,
)Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Button, Color, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
overlay_demo(
self.demo_overlay("ad-icon"),
"ad-icon",
"Open with a status icon",
AlertDialog::new("Heads up").id("alert-dialog-icon")
.description("The status picks the icon, so a warning dialog shows the warning glyph.")
.is_open(self.demo_overlay("ad-icon"))
.status(Color::Warning)
.child(AlertDialogCloseTrigger::new())
.on_open_change(cx.listener(|this, v: &bool, _, cx| {
this.set_demo_flag("ad-icon", *v);
cx.notify();
}))
.into_any_element(),
cx,
)Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Backdrop, Button, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
overlay_demo(
self.demo_overlay("ad-custom-bd"),
"ad-custom-bd",
"Open with a blurred backdrop",
AlertDialog::new("Blurred").id("alert-dialog-custom-bd")
.description("The page behind the panel is blurred.")
.is_open(self.demo_overlay("ad-custom-bd"))
.backdrop(herogpui::core::Backdrop::Blur)
.child(AlertDialogCloseTrigger::new())
.on_open_change(cx.listener(|this, v: &bool, _, cx| {
this.set_demo_flag("ad-custom-bd", *v);
cx.notify();
}))
.into_any_element(),
cx,
)Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Button, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
overlay_demo(
self.demo_overlay("ad-dismiss"),
"ad-dismiss",
"Open a non-dismissable dialog",
AlertDialog::new("Confirm first").id("alert-dialog-dismiss")
.description("The backdrop and Escape are both inert; the composed X and the actions still close.")
.is_open(self.demo_overlay("ad-dismiss"))
.is_dismissible(false)
.is_keyboard_dismiss_disabled(true)
.child(AlertDialogCloseTrigger::new())
.on_open_change(cx.listener(|this, v: &bool, _, cx| {
this.set_demo_flag("ad-dismiss", *v);
cx.notify();
}))
.into_any_element(),
cx,
)Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Button, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
gpui::div()
.flex()
.flex_col()
.w_full()
.gap(px(12.))
.children(vec![
overlay_demo(
self.demo_overlay("ad-close"),
"ad-close",
"Open (destructive confirm)",
AlertDialog::new("Delete for ever?").id("alert-dialog-close")
.description("A composed footer retires the built-in pair: the danger confirm and the cancel are ordinary Buttons the caller wires to close. The X is not composed here, so the corner slot is bare.")
.is_open(self.demo_overlay("ad-close"))
.footer_child(
Button::new("alert-dialog-close-cancel")
.label("Keep")
.variant(Variant::Tertiary)
.on_press(cx.listener(|this, _, _, cx| {
this.set_demo_flag("ad-close", false);
cx.notify();
})),
)
.footer_child(
Button::new("alert-dialog-close-confirm")
.label("Delete")
.variant(Variant::Danger)
.on_press(cx.listener(|this, _, _, cx| {
this.set_demo_flag("ad-close", false);
cx.notify();
})),
)
.on_open_change(cx.listener(|this, v: &bool, _, cx| {
this.set_demo_flag("ad-close", *v);
cx.notify();
}))
.into_any_element(),
cx,
),
overlay_demo(
self.demo_overlay("ad-pending"),
"ad-pending",
"Open (pending confirm)",
AlertDialog::new("Deploying").id("alert-dialog-pending")
.description("A composed footer Button carries the pending state: it shows a spinner and swallows the press while the action is in flight, so no close is reported; only the cancel closes.")
.is_open(self.demo_overlay("ad-pending"))
.footer_child(
Button::new("alert-dialog-pending-cancel")
.label("Cancel")
.variant(Variant::Tertiary)
.on_press(cx.listener(|this, _, _, cx| {
this.set_demo_flag("ad-pending", false);
cx.notify();
})),
)
.footer_child(
Button::new("alert-dialog-pending-confirm")
.label("Deploy")
.is_pending(true),
)
.on_open_change(cx.listener(|this, v: &bool, _, cx| {
this.set_demo_flag("ad-pending", *v);
cx.notify();
}))
.into_any_element(),
cx,
),
])Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Button, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::{AnyElement, Context, px};
use herogpui::gpui;
overlay_demo(
self.demo_overlay("ad-anim"),
"ad-anim",
"Open and watch the panel",
AlertDialog::new("Animated").id("alert-dialog-anim")
.description("The panel shrinks in from 105% over 250ms and leaves at 95% over 100ms.")
.is_open(self.demo_overlay("ad-anim"))
.child(AlertDialogCloseTrigger::new())
.on_open_change(cx.listener(|this, v: &bool, _, cx| {
this.set_demo_flag("ad-anim", *v);
cx.notify();
}))
.into_any_element(),
cx,
)Also calls overlay_min_h, el_id, overlay_demo (included when you copy).
Runs in a view's render: self is the view holding this example's state and cx is its Context<Self>.
use herogpui::prelude::{AlertDialog, AlertDialogCloseTrigger, Button, Chip, ChipLabel, ChipVariant, Color, Variant};
use herogpui::gpui::prelude::*;
use herogpui::gpui::px;
use herogpui::gpui;
{
let open = self.demo_overlay("ad-custom");
overlay_min_h(
gpui::div()
.relative()
.flex()
.flex_col()
.items_center()
.w_full(),
open,
120.,
)
.child(
gpui::div()
.id("alert-dialog-custom-trigger")
.cursor_pointer()
.child(
Chip::new()
.color(Color::Danger)
.variant(ChipVariant::Soft)
.child(ChipLabel::new().child("Delete account")),
)
.on_click(cx.listener(|this, _, _, cx| {
this.set_demo_flag("ad-custom", true);
cx.notify();
})),
)
.child(
AlertDialog::new("Delete this account?").id("alert-dialog-custom")
.description("Any element can open an alert dialog; a composed CloseTrigger draws the corner X and a composed footer owns the danger confirm.")
.is_open(open)
.child(AlertDialogCloseTrigger::new())
.footer_child(
Button::new("alert-dialog-custom-cancel")
.label("Cancel")
.variant(Variant::Tertiary)
.on_press(cx.listener(|this, _, _, cx| {
this.set_demo_flag("ad-custom", false);
cx.notify();
})),
)
.footer_child(
Button::new("alert-dialog-custom-confirm")
.label("Delete account")
.variant(Variant::Danger)
.on_press(cx.listener(|this, _, _, cx| {
this.set_demo_flag("ad-custom", false);
cx.notify();
})),
)
.on_open_change(cx.listener(|this, v: &bool, _, cx| {
this.set_demo_flag("ad-custom", *v);
cx.notify();
}))
)
.into_any_element()
}Also calls overlay_min_h (included when you copy).
Helpers used by these examples
Plain functions over the public API, defined once here and copied with each example that calls them.
fn overlay_min_h(mut frame: gpui::Div, open: bool, height: f32) -> gpui::Div {
if open {
frame = frame.min_h(px(height));
}
frame
}fn el_id(s: String) -> gpui::ElementId {
gpui::ElementId::Name(s.into())
}/// One overlay demo: the trigger, and the panel it opens.
///
/// An overlay needs a positioned ancestor and enough height to show the panel,
/// and each demo owns its own open flag -- v3's pages show one variant per
/// example, so a shared flag would open all of them at once.
fn overlay_demo(
open: bool,
key: &'static str,
label: &str,
panel: AnyElement,
cx: &mut Context<'_, Gallery>,
) -> AnyElement {
// The panel is `absolute inset-0` inside this frame, and v3's body is
// `min-h-0 flex-1`, so a short frame squeezes the body to nothing.
// Reserve that height only while the panel is open; a closed trigger
// sitting in a 320px hole was the empty-card gap on overlay pages.
overlay_min_h(
gpui::div()
.relative()
.flex()
.flex_col()
.items_center()
.w_full(),
open,
320.,
)
.child(
Button::new(format!("{key}-open"))
.label(label.to_owned())
.variant(Variant::Secondary)
.on_press(cx.listener(move |this, _, _, cx| {
this.set_demo_flag(key, true);
cx.notify();
})),
)
.child(panel)
.into_any_element()
}Anatomy
Rust types
Alert Dialog is assembled from these builders. The API reference lists each one.
Customization
Shared appearance belongs on ThemeBuilder::components and .recipe("name"). Typed builders change how Alert Dialog looks at one call site. Every builder also carries sx for placement, width and flex: it takes GPUI's own styling methods and refines them over the component's root after the theme, so an instance override wins. Behaviour builders live in the API reference below.
Styling
| Method | Values | Description |
|---|---|---|
backdrop(Backdrop)Partial | Backdrop::Opaque | Backdrop::Blur | Backdrop::Transparent | Backdrop overlay style; all three variants render, but gpui has no backdrop-filter, so Blur draws a lighter scrim rather than a blur. |
placement(ModalPlacement) | ModalPlacement::Auto | ModalPlacement::Center | ModalPlacement::Top | ModalPlacement::Bottom | Dialog position on screen; all four anchor the panel, and the explicit top/bottom placements carry v3's ±4px entry slide while centered/auto desktop layouts stay still. |
size(AlertDialogSize) | AlertDialogSize::Xs | AlertDialogSize::Sm | AlertDialogSize::Md | AlertDialogSize::Lg | AlertDialogSize::Cover | Alert Dialog size variant; the four max-width steps match and Cover fills the container's content box. There is no `full`: a critical confirmation never fills the viewport edge to edge. |
// The one slot for caller-owned low-level styling: GPUI's
// styling methods, refined over the root element last.
.sx(|el| {
el.bg(gpui::rgba(0xffa500ff)) // background
.text_color(gpui::rgba(0x000000ff)) // text
.w(gpui::px(13.)) // size
.h(gpui::px(12.))
})API reference
Against HeroUI v3.2.6: 20 entries ported, 12 partial, 17 not ported. Partial rows are marked in the tables; entries not ported are listed under each table with the reason.
Builders
| Builder | Values | Default | Description |
|---|---|---|---|
new(Partial | AnyElement | — | Trigger and container elements; composes the panel itself and the ParentElement::extend children land in the body slot, with the trigger left to the caller. |
backdrop(Partial | Backdrop:: | Backdrop:: | Backdrop overlay style; all three variants render, but gpui has no backdrop-filter, so Blur draws a lighter scrim rather than a blur. |
is_dismissible( | true | | false | Close on backdrop click; gates the outside-press dismissal on it. Like v3, the gate covers only the scrim — the close trigger renders in every documented example, including the isDismissable={false} one. |
is_keyboard_dismiss_disabled( | true | | true | Disable ESC key to close; Escape is already off by default here, so allowing it is the opt-in. |
is_open( | true | | — | Controlled open state; the owner, not the dialog, decides the next render. |
on_open_change( | Fn( | — | Open state change handler; fires with false on every close path — the composed X, the backdrop, Escape and the built-in confirm/cancel stand-in — and never through onCancel. A composed footer's Buttons own their own close wiring. |
placement( | ModalPlacement:: | ModalPlacement:: | Dialog position on screen; all four anchor the panel, and the explicit top/bottom placements carry v3's ±4px entry slide while centered/auto desktop layouts stay still. |
size( | AlertDialogSize:: | AlertDialogSize:: | Alert Dialog size variant; the four max-width steps match and Cover fills the container's content box. There is no `full`: a critical confirmation never fills the viewport edge to edge. |
new(Partial | AnyElement | — | Header content (typically Icon and Heading); renders the header column from the title and the optional status icon, without a composable children slot. |
new(Partial | AnyElement | — | Heading text; accepts a string via the title argument instead of composed children. |
description + ParentElement::Partial | AnyElement | — | Body content; one scrolling slot holds the description and the ParentElement::extend children, but v3's per-part prop surface is not exposed. |
footer_child( | AnyElement | — | Footer content (typically action buttons); the port's built-in confirm/cancel pair stands in for v3's slot="close" compositions and retires whole the moment the caller composes footer children — a composed footer Button owns its own danger and pending spellings and its own close wiring. |
status(Partial | AnyElement | — | Custom icon element; draws the status glyph itself, so composed children are not supported. |
status( | 'default' | | "danger" | Status colour variant; the port's status defaults to None, which renders no icon at all — the analogue of not composing AlertDialog.Icon in v3. The role colour, soft surface and glyph all match v3's icon map: info for default and accent, then success, warning and danger, each embedded with upstream geometry. |
new( | AnyElement | — | The dialog composes this part as a child: without children it draws the built-in neutral CloseButton wired to onOpenChange(false) alone — never on_cancel — and custom children replace the CloseButton's glyph while the press stays automatically wired to close the same way. |
Not ported16 HeroUI entries not ported
| HeroUI v3 | Why it is not ported |
|---|---|
AlertDialog.Trigger.children | Custom trigger content; renders no trigger slot, so callers drive is_open from their own control. |
AlertDialog.Trigger.className | Styles for the trigger. |
AlertDialog.Backdrop.className | Backdrop styles. |
AlertDialog.Backdrop.UNSTABLE_portalContainer | Custom portal container; renders the overlay inline in the element tree, and gpui has no portal. |
AlertDialog.Container.className | Container styles. |
AlertDialog.Dialog.className | Styles for the dialog. |
AlertDialog.Dialog.role | ARIA role override; gpui exposes no accessibility tree. |
AlertDialog.Dialog.aria-label | Accessibility label; gpui exposes no accessibility tree. |
AlertDialog.Dialog.aria-labelledby | ID of the label element; gpui exposes no accessibility tree. |
AlertDialog.Dialog.aria-describedby | ID of the description element; gpui exposes no accessibility tree. |
AlertDialog.Header.className | Styles for the header. |
AlertDialog.Heading.className | Styles for the heading. |
AlertDialog.Body.className | Styles for the body. |
AlertDialog.Footer.className | Styles for the footer. |
AlertDialog.Icon.className | Styles for the icon. |
AlertDialog.CloseTrigger.className | Close trigger styles. |
Parts
| Part | Description |
|---|---|
AlertDialog | Composition root that owns the open state and the focus trap; configured callbacks receive every enabled dismissal path. |
AlertDialog | Scrim behind the panel, dimmed but press-less; outside presses dismiss through the panel's own bounds. |
AlertDialog | Window-pinning wrapper that applies the placement alignment and the 40px desktop inset. |
AlertDialog | The panel itself: overlay surface, 24px inset, max-height cap and the overflow clip that keeps the footer pinned. |
AlertDialogPartial | Title column with a 12px gap; the optional icon is a child of it, above the heading, not a floating corner disc. |
AlertDialogPartial | 16px medium foreground title; accepts a string via the title argument instead of composed children. |
AlertDialog | One scrolling slot holding the wrapping description and composed children, capped under the panel and given flex-1 only when Cover fixes the panel height. |
AlertDialog | End-aligned action row: the built-in cancel/confirm pair stands in for v3's slot="close" buttons and retires whole the moment the caller composes footer children, which own their own danger and pending spellings. |
AlertDialogPartial | 40px glyph box above the heading; tints it from a status role rather than composed children. |
AlertDialogCloseTrigger | Composed part pinned 16px from the top end: the default content is the built-in neutral CloseButton wired to onOpenChange(false) alone regardless of is_dismissible, and custom children replace the glyph while staying wired to close the same way. With no on_open_change to wire the part draws nothing. |
Not ported1 HeroUI entry not ported
| HeroUI v3 | Why it is not ported |
|---|---|
AlertDialog.Trigger | Element that opens the alert dialog; renders no trigger slot, so callers drive is_open from their own control. |
States
| State | Builder | Description |
|---|---|---|
FocusPartial | focus_handle | Applied to the trigger, the dialog and the close button; claims the panel's focus handle and traps Tab, and the close button rings from its own tab stop, while the trigger is not a part here. |
Hover | CloseButton hover surface | Applied to the close button on hover. |
ActivePartial | CloseButton .active centered root-bounds shrink | Applied to the trigger and the close button when pressed; the close button uses a centered root-bounds shrink while fixed child content remains unscaled, and the absent trigger has no surface. |
Entering | OverlayPhase::Open | Applied during the opening animation: the scrim fades at 150ms and the panel fades while zooming in from 105% at 250ms, with the four-pixel top/bottom placement slide in the same transition. |
Exiting | overlay_phase::Exiting | Applied during the closing animation; the panel and the scrim stay mounted for the 100ms fade/zoom out, which carries no slide in either. |
Placement | ModalPlacement anchored match | Auto, top, center and bottom anchor the dialog and choose the container alignment; top and bottom add the ±4px entry slide, while desktop Auto and Center remain zero-offset. |