All skills
lassejlv avatar

/build-gpui-apps

@52f4cfd
by Lasselassejlv/skills50 stars
1

Build, scaffold, refactor, debug, review, and validate native Rust desktop applications with GPUI. Recommend GPUI Kit and ask before adopting it; use gpui_kit imports after agreement, or preserve the chosen upstream GPUI stack. Includes the merged GPUI Kit component and design skills, full application/Base/Component/Shell documentation, coding and design guides, state, actions, async, input, accessibility, motion, themes, native integration, packaging, auto updates, testing, and production delivery. Use paper-to-gpui when the primary task is faithfully translating a selected Paper.design frame into an existing view.

Use this Skill: https://skilld.dev/gh/lassejlv/skills/build-gpui-apps

This session only. Nothing lands on disk.

referencesgpui-kitupstreamcomponentdialog.md

≈4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

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"))
            )
    })

Styled Footer

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

Method Description
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

Documentation license: original prose and illustrations for which GPUI Kit holds licensing rights are also offered under CC BY 4.0. When copying or adapting, credit GPUI Kit, link the source (https://gpui-kit.com/component/dialog) and https://creativecommons.org/licenses/by/4.0/, and indicate changes. Code examples and software source use Apache-2.0; third-party material retains its terms; existing Apache-2.0 permissions remain.

Bundled from GPUI Kit. Documentation prose: CC BY 4.0; code examples: Apache-2.0. Changes: documentation links localized, asset URLs made absolute, and this attribution added.

Source: SKILL.md on GitHub

No alerts3d3 checks · Risk SAFE
  • Gen Agent Trust Hub3d

    The skill provides comprehensive documentation and reference material for building native desktop applications using Rust and GPUI. No security risks, prompt injections, or malicious behaviors were identified. External dependencies originate from reputable organizations in the Rust ecosystem.

  • Socket3d

    No alerts

  • Snyk3d

    Risk: LOW · No issues

Signed by skilld at 52f4cfd. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 4 days ago

README badge

README badge for lassejlv/skills/build-gpui-apps