Dialog#

Dialog creates a fully custom modal window. Provide a content_builder= function to lay out any widgets, and a buttons= list to define the footer.

Dialog — light theme Dialog — dark theme

Usage#

Reach for Dialog when no built-in fits — it is a blank modal you fill with a content_builder= body and a buttons= footer, and show() blocks until it returns a result. For the common cases, prefer the verb dialogs (alert/confirm, ask_*) or a FormDialog.

Content builder#

The dialog’s content area is set as the active parent, so content_builder fills it like an App body — no parent= needed. padding= and gap= configure the content area:

from bootstack.dialogs import Dialog

def build():
    bs.Label("New version available", font="heading-sm")
    bs.Label("bootstack 2.1.0 is ready to install.")

dlg = Dialog(title="Update", content_builder=build, padding=24, gap=12)
dlg.show()

Declare a single parameter (def build(content):) if you want an explicit handle to the content container — for example to nest a Row or pass it as a parent=.

Button roles#

role= controls button styling and keyboard shortcuts automatically.

Role

Behavior

'primary'

Blue solid. Focused by default; triggered by Enter when default=True.

'secondary'

Gray solid. For neutral actions (OK, Dismiss).

'danger'

Red solid. For destructive actions. Not focused by default.

'cancel'

Gray outline. Triggered by Escape.

Reading the result#

Each DialogButton carries a result= value that dialog.result is set to when that button is clicked:

dlg = Dialog(
    title="Save changes?",
    content_builder=build,
    buttons=[
        DialogButton("Save",    role="primary", result="save",    default=True),
        DialogButton("Discard", role="danger",  result="discard"),
        DialogButton("Cancel",  role="cancel"),
    ],
)
dlg.show()

if dlg.result == "save":
    save()
elif dlg.result == "discard":
    discard()

Refusing a press#

A button’s command= can decline the press it was given. Return False and the dialog records no result and stays open, so the user can correct the input and try again; return anything else — including None — and the press completes as usual:

name = bs.Signal("")

def build():
    bs.Label("Project name")
    bs.TextField(textsignal=name)

def save(dlg):
    if not name():
        bs.toast("A name is required.")
        return False        # refused: the dialog stays open

dlg = Dialog(
    title="New project",
    content_builder=build,
    buttons=[
        DialogButton("Save", role="primary", result="save", command=save, default=True),
        DialogButton("Cancel", role="cancel"),
    ],
)
dlg.show()

if dlg.result == "save":
    create_project(name())

This is per press, not per button — the same button accepts the next press once the input is valid. It applies to the Enter key as well, which triggers the default button through the same command.

Note

Bind the content to a Signal when you need its value afterward, the way name is used above. show() returns once the window has closed, and the widgets the builder made are gone by then — the signal holds the value independently of them, so it is still there to read.

Dialog modes#

mode= controls how the dialog interacts with the rest of the app.

Mode

Behavior

'modal'

Blocks the parent window until closed. Default.

'popover'

Closes automatically when focus leaves the dialog.

'sheet'

Like 'modal' on Windows/Linux; renders as a Cocoa sheet on macOS.

Positioning#

By default, dialogs center on the parent window. Override with anchor_to= to position relative to a widget, the cursor, or the screen:

dlg.show(anchor_to=my_button, anchor_point="s", window_point="n")

dlg.show(anchor_to="cursor")

dlg.show(position=(400, 300))

See also#

Message Dialogsalert() and confirm() for common notifications.

Form DialogFormDialog for structured data-entry forms.

Filter DialogFilterDialog for multi-select list dialogs.

API#

The complete reference for Dialog and DialogButton lives on the Dialogs API page. At a glance:

Dialog

A flexible dialog window using the builder pattern.

DialogButton

Specification for a dialog button.

Full Example#

 1
 2from bootstack.dialogs import Dialog, DialogButton
 3
 4
 5def show_simple():
 6    # The content area is the active parent — build the body like an App body.
 7    def build():
 8        bs.Label("Delete 3 selected items?")
 9        bs.Label("This action cannot be undone.", font="caption")
10
11    dlg = Dialog(
12        title="Confirm deletion",
13        content_builder=build,
14        padding=(24, 20),
15        buttons=[
16            DialogButton("Delete", role="danger", result="delete"),
17            DialogButton("Cancel", role="cancel"),
18        ],
19    )
20    dlg.show()
21
22def show_info():
23    def build():
24        bs.Label("New version available", font="heading-sm")
25        bs.Label("bootstack 2.1.0 is ready to install.")
26        bs.Label("Release notes: improved themes, new widgets.", font="caption")
27
28    dlg = Dialog(
29        title="Update available",
30        content_builder=build,
31        padding=24,
32        gap=12,
33        buttons=[
34            DialogButton("Install now", role="primary", result="install", default=True),
35            DialogButton("Later",       role="cancel"),
36        ],
37        min_size=(420, 180),
38    )
39    dlg.show()
40
41def show_anchored():
42    def build():
43        bs.Label("Saved to Documents/report.pdf")
44
45    dlg = Dialog(
46        title=" ",
47        content_builder=build,
48        padding=16,
49        buttons=[DialogButton("OK", role="secondary", result=True, default=True)],
50        min_size=(320, 100),
51    )
52    dlg.show()
53
54with bs.App(title="Dialog", size=(680, 200), padding=20, gap=16) as app:
55
56    bs.Label("Custom Dialog", font="heading-sm")
57    with bs.Row(gap=8):
58        bs.Button("Delete confirmation", on_click=show_simple)
59        bs.Button("Update notice",       on_click=show_info)
60        bs.Button("Simple message",      on_click=show_anchored)
61
62app.run()