Dialog

Dialog component for creating dialogs, confirmations, and alerts. Supports overlay, keyboard shortcuts, and various customizations.

#Import

use gpui_kit::component::dialog::DialogButtonProps;
use gpui_kit::component::WindowExt;

#Usage

#Where dialogs render

The window’s Root automatically mounts and renders dialogs. Open the window with gpui_kit::open_window, or wrap the application view in Root::new. Application views do not render overlay layers themselves.

#Basic Dialog

window.open_dialog(cx, |dialog, _, _| {
    dialog
        .title("Welcome")
        .child("This is a dialog dialog.")
})

#Form Dialog

let input = cx.new(|cx| InputState::new(window, cx));

window.open_dialog(cx, |dialog, _, _| {
    dialog
        .title("User Information")
        .child(
            v_flex()
                .gap_3()
                .child("Please enter your details:")
                .child(Input::new(&input))
        )
        .footer(|_, _, _, _| {
            vec![
                Button::new("ok")
                    .primary()
                    .label("Submit")
                    .on_click(|_, window, cx| {
                        window.close_dialog(cx);
                    }),
                Button::new("cancel")
                    .label("Cancel")
                    .on_click(|_, window, cx| {
                        window.close_dialog(cx);
                    }),
            ]
        })
})

#Dialog with Icon

window.open_dialog(cx, |dialog, _, cx| {
    dialog
        .child(
            h_flex()
                .gap_3()
                .child(Icon::new(IconName::TriangleAlert)
                    .size_6()
                    .text_color(cx.theme().warning))
                .child("This action cannot be undone.")
        )
})

#Scrollable Dialog

use gpui_kit::component::text::markdown;

window.open_dialog(cx, |dialog, window, cx| {
    dialog
        .h(px(450.))
        .title("Long Content")
        .child(markdown(long_markdown_text))
})

A dialog never extends past the window. Its width is capped at the viewport minus a 16px margin on each side, and its height at the space between its top offset and a 16px bottom margin, so the title and footer stay visible while the body scrolls. w, max_w, h, and margin_top apply within those limits; a dialog that already fits keeps its requested size and default position.

#Dialog Options

window.open_dialog(cx, |dialog, _, _| {
    dialog
        .title("Custom Dialog")
        .overlay(true)              // Show overlay (default: true)
        .overlay_closable(true)     // Click overlay to close (default: true)
        .keyboard(true)             // ESC to close (default: true)
        .close_button(false)        // Show close button (default: true)
        .child("Dialog content")
})

#Action Buttons

A Dialog puts its own buttons in the footer and has them dispatch Confirm or Cancel; on_ok and on_cancel decide what Enter and Esc do. For a confirmation with default buttons, use AlertDialog.

#Nested Dialogs

window.open_dialog(cx, |dialog, _, _| {
    dialog
        .title("First Dialog")
        .child("This is the first dialog")
        .footer(|_, _, _, _| {
            vec![
                Button::new("open-another")
                    .label("Open Another Dialog")
                    .on_click(|_, window, cx| {
                        window.open_dialog(cx, |dialog, _, _| {
                            dialog
                                .title("Second Dialog")
                                .child("This is nested")
                        });
                    }),
            ]
        })
})

#Custom Styling

window.open_dialog(cx, |dialog, _, cx| {
    dialog
        .rounded(cx.theme().radius_lg)
        .bg(cx.theme().cyan)
        .text_color(cx.theme().info_foreground)
        .title("Custom Style")
        .child("Styled dialog content")
})

#Custom Padding

window.open_dialog(cx, |dialog, _, _| {
    dialog
        .p_3()                      // Custom padding
        .title("Custom Padding")
        .child("Dialog with custom spacing")
})

#Close Dialog Programmatically

The close_dialog method can be used to close the active dialog from anywhere within the window context.

// Close top level active dialog.
window.close_dialog(cx);

// Close and perform action
Button::new("submit")
    .primary()
    .label("Submit")
    .on_click(|_, window, cx| {
        // Do something
        window.close_dialog(cx);
    })

#Declarative API

The Dialog component now supports a declarative API that provides a more React-like component composition pattern using dedicated header, title, description, and footer components.

#Import

use gpui_kit::component::dialog::{
    Dialog, DialogHeader, DialogTitle, DialogDescription, DialogFooter,
};

#Trigger-based Dialog

The trigger-based approach allows you to create a dialog that opens when a trigger element is clicked. The dialog is defined inline with the trigger.

Dialog::new(cx)
    .trigger(
        Button::new("open-dialog")
            .outline()
            .label("Open Dialog")
    )
    .content(|content, _, cx| {
        content
            .child(
                DialogHeader::new()
                    .child(DialogTitle::new().child("Account Created"))
                    .child(DialogDescription::new().child(
                        "Your account has been created successfully!",
                    ))
            )
            .child(
                DialogFooter::new()
                    .border_t_1()
                    .border_color(cx.theme().border)
                    .bg(cx.theme().muted)
                    .child(
                        Button::new("cancel")
                            .outline()
                            .label("Cancel")
                            .on_click(|_, window, cx| {
                                window.close_dialog(cx);
                            })
                    )
                    .child(
                        Button::new("ok")
                            .primary()
                            .label("Save Changes")
                    )
            )
    })

#Content Builder Pattern

Use the content builder pattern with window.open_dialog for more control over dialog creation:

window.open_dialog(cx, |dialog, _, _| {
    dialog
        .w(px(400.))
        .content(|content, _, _| {
            content
                .child(
                    DialogHeader::new()
                        .child(DialogTitle::new().child("Custom Width"))
                        .child(DialogDescription::new().child(
                            "This dialog has a custom width of 400px.",
                        ))
                )
                .child(div().child(
                    "Content area with custom width configuration."
                ))
                .child(
                    DialogFooter::new()
                        .justify_center()
                        .child(
                            Button::new("cancel")
                                .flex_1()
                                .outline()
                                .label("Cancel")
                                .on_click(|_, window, cx| {
                                    window.close_dialog(cx);
                                })
                        )
                        .child(
                            Button::new("done")
                                .flex_1()
                                .primary()
                                .label("Done")
                                .on_click(|_, window, cx| {
                                    window.close_dialog(cx);
                                })
                        )
                )
        })
})

#Declarative Components

#DialogHeader

Container for the dialog’s title and description section.

DialogHeader::new()
    .child(DialogTitle::new().child("Title"))
    .child(DialogDescription::new().child("Description"))

#DialogTitle

Displays the main title of the dialog with semantic styling.

DialogTitle::new()
    .child("Account Settings")

#DialogDescription

Displays descriptive text below the title with muted styling.

DialogDescription::new()
    .child("Update your account settings and preferences here.")

#DialogFooter

Container for action buttons and footer content. Automatically applies proper spacing and alignment.

DialogFooter::new()
    .bg(cx.theme().muted)
    .border_t_1()
    .border_color(cx.theme().border)
    .child(Button::new("cancel").outline().label("Cancel"))
    .child(Button::new("save").primary().label("Save"))

#Form Dialog with Declarative API

let name_input = cx.new(|cx| InputState::new(window, cx));
let email_input = cx.new(|cx| InputState::new(window, cx));

Dialog::new(cx)
    .trigger(Button::new("edit-profile").label("Edit Profile"))
    .content(|content, _, cx| {
        content
            .child(
                DialogHeader::new()
                    .child(DialogTitle::new().child("Edit Profile"))
                    .child(DialogDescription::new().child(
                        "Make changes to your profile here. Click save when done."
                    ))
            )
            .child(
                v_flex()
                    .gap_4()
                    .py_4()
                    .child(
                        v_flex()
                            .gap_2()
                            .child("Name")
                            .child(Input::new(&name_input).placeholder("Enter your name"))
                    )
                    .child(
                        v_flex()
                            .gap_2()
                            .child("Email")
                            .child(Input::new(&email_input).placeholder("Enter your email"))
                    )
            )
            .child(
                DialogFooter::new()
                    .child(Button::new("cancel").outline().label("Cancel"))
                    .child(Button::new("save").primary().label("Save Changes"))
            )
    })

Customize the footer appearance with background colors, borders, and alignment:

DialogFooter::new()
    .justify_center()        // Center align buttons
    .bg(cx.theme().muted)    // Background color
    .border_t_1()            // Top border
    .border_color(cx.theme().border)
    .child(Button::new("btn1").flex_1().label("Cancel"))
    .child(Button::new("btn2").flex_1().primary().label("Confirm"))

#DialogContent Container

The DialogContent component provides a flexible container for dialog body content:

use gpui_kit::component::dialog::DialogContent;

window.open_dialog(cx, |dialog, _, _| {
    dialog.content(|content, _, cx| {
        content
            .child(DialogHeader::new()
                .child(DialogTitle::new().child("Settings"))
                .child(DialogDescription::new().child("Configure your preferences"))
            )
            .child(
                div()
                    .py_4()
                    .child("Main content area")
            )
            .child(DialogFooter::new()
                .child(Button::new("close").label("Close"))
            )
    })
})

#API Reference - Declarative Components

#Dialog

MethodDescription
new(cx)Create a new Dialog (no longer requires window param)
trigger(element)Set trigger element that opens the dialog
content(builder)Set content using a builder function
w(px) / width(px)Set dialog width
max_w(px)Set maximum width
margin_top(px)Set top margin
overlay(bool)Show/hide overlay (default: true)
overlay_closable(bool)Allow closing by clicking overlay (default: true)
keyboard(bool)Allow closing with ESC key (default: true)
close_button(bool)Show/hide close button (default: true)

#DialogContent

Container for dialog body content. Automatically applies padding and flex layout.

DialogContent::new()
    .child(DialogHeader::new()...)
    .child(/* your content */)
    .child(DialogFooter::new()...)

#DialogHeader

Container for title and description. Automatically applies vertical flex layout with proper gap.

DialogHeader::new()
    .child(DialogTitle::new().child("Title"))
    .child(DialogDescription::new().child("Description"))

#DialogTitle

Displays the dialog title with semantic styling (font-semibold, proper line-height).

DialogTitle::new()
    .child("Dialog Title")

#DialogDescription

Displays descriptive text with muted foreground color and proper text sizing.

DialogDescription::new()
    .child("This is a description text that provides more context.")

#DialogFooter

Container for footer buttons with automatic spacing and alignment.

DialogFooter::new()
    .justify_end()  // Right align (default)
    .child(Button::new("btn1").label("Cancel"))
    .child(Button::new("btn2").primary().label("OK"))

#Breaking Changes

#Dialog::new() Signature Change

The Dialog::new() constructor no longer requires a window parameter:

// Old API (deprecated)
Dialog::new(window, cx)

// New API
Dialog::new(cx)

#Content Builder Function

The .content() method now accepts a builder function instead of a pre-built DialogContent:

// Old approach (still works)
dialog.child(DialogHeader::new()...)

// New declarative API
dialog.content(|content, window, cx| {
    content
        .child(DialogHeader::new()...)
        .child(DialogFooter::new()...)
})

#Best Practices

  1. Use Declarative Components: Prefer DialogHeader, DialogTitle, DialogDescription, and DialogFooter for consistent styling
  2. Trigger-based for Simple Cases: Use the trigger pattern for straightforward dialogs that open from a button
  3. Builder Pattern for Complex Dialogs: Use window.open_dialog with content builder for dialogs requiring complex logic or state
  4. Semantic Structure: Always include DialogHeader with title and description for accessibility
  5. Consistent Footer: Use DialogFooter for all action buttons to maintain visual consistency
  6. Proper Sizing: Explicitly set dialog width when content requires specific dimensions