Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

MessageBox

MessageBox preview

MessageBox — QMessageBox-style alert dialog.

Public types

KindName
enumMessageBoxSeverity — Alert severity level
enumButtonRole — Semantic role of a message-box button
enumStandardButton — The Qt-modeled catalog of standard buttons
structMessageBoxButton — A single button placement inside a MessageBox, including an optional per-instance label override
enumMessageBoxButtons — Pre-built button bundles covering the common MessageBox shapes
enumMessageBoxDismissal — How a MessageBox came to close
structMessageBoxResult — Report passed to MessageBox::on_result when the dialog closes
structMessageBox — A modal alert dialog that displays a severity icon, title, body text, and one or more buttons
traitEventContextMessageBoxExt — Extension trait on EventContext for ergonomic MessageBox presentation

Public functions

MessageBox

StandardButton

ReturnsFunction
Methods
ButtonRolerole()
&'static strintent_name()
LocalizedStringdefault_label()

MessageBoxButton

ReturnsFunction
Constructors
Selfstandard(kind: StandardButton)
Builder methods
Selflabel(label: impl Into<LocalizedString>)

MessageBoxResult

ReturnsFunction
Methods
boolwas_dismissed()

EventContextMessageBoxExt

ReturnsFunction
Methods
present_message_box(mb: MessageBox)

Detailed description

A higher-level surface built on top of ModalContainer for the classic "tell the user something and ask for a response" pattern: unsaved-changes prompts, error surfaces, confirmation dialogs, and informational notices. Mirrors QMessageBox (Qt), NSAlert (AppKit), and SwiftUI's .alert(...) while staying inside Teksilo's idioms — closure result handlers, Signal/Prop reactivity, Intent/Action/Shortcut routing for keyboard defaults, and AccessKit Role::AlertDialog accessibility.

Quick tour

use teksilo::prelude::*;
use teksilo::widgets::{MessageBox, MessageBoxButtons, StandardButton};

fn on_close(ctx: &mut EventContext) {
    MessageBox::question(lit!("Save changes?"))
        .text(lit!("You have unsaved changes in report.skrib."))
        .informative_text(lit!("Your changes will be lost if you don't save them."))
        .buttons(MessageBoxButtons::SaveDiscardCancel)
        .default_button(StandardButton::Save)
        .escape_button(StandardButton::Cancel)
        .on_result(|r, ctx| match r.button {
            StandardButton::Save => save_and_close(ctx),
            StandardButton::Discard => close(ctx),
            _ => {}
        })
        .present(ctx);
}
# fn save_and_close(_: &mut EventContext) {}
# fn close(_: &mut EventContext) {}

Severity

MessageBoxSeverity controls the icon drawn beside the title and its tint:

  • Information — info glyph, status_info_fg tint.
  • Question — question mark glyph, accent tint.
  • Warning — exclamation triangle, status_warning_fg tint.
  • Critical — X-mark circle, status_error_fg tint. Also disables click-outside dismissal (Qt convention).
  • None — no icon, no tint.

Severity is conveyed through the icon + title + text. Per Teksilo's Int UI baseline, buttons are never colored as "destructive": destructive intent lives in the dialog's severity and wording, not in the button. See crate::button for details.

Default & escape buttons

  • default_button — activated by Enter (widget-scoped shortcut) and receives initial focus on open (via ModalRequest::focus_target plus Widget::initial_focus_hint). Styled with ButtonVariant::Filled.
  • escape_button — activated by Escape. The fallback logic (for presets with no explicit escape_button) picks: explicit escape_button → first Reject-role button → Cancel → last button.

Each preset supplies a default: Ok for Ok and OkCancel, Save for SaveDiscardCancel, Retry for RetryIgnoreAbort, and No for YesNo and YesNoCancel.

The Yes/No default is the negative answer on purpose. An Ok/Cancel box confirms something the user just asked for, so Ok is the answer they meant. A Yes/No box asks a question they did not initiate, and it is overwhelmingly asked before something irreversible — "Delete this?", "Discard your changes?". Defaulting to Yes means Enter destroys, and Enter is what a keyboard user presses on a dialog they have not finished reading. Where the question is safe, default_button puts Yes back in one reviewable line; the reverse default cannot be reviewed, because there is nothing on the screen to review.

It matters more than it looks, because no platform announces which button is the default: Node::keyboard_shortcut appears in none of the three AccessKit adapters, so a screen-reader user discovers the default only by pressing Enter. Where focus lands is the whole contract.

Title and button alignment

MessageBox::title_alignment places the title in the header's text column (default Leading) and MessageBox::button_alignment places the button row (default Trailing), both as teksilo_tokens::HAlignment. macOS alerts centre both; Windows and GNOME keep the title leading and the buttons trailing, which is the default. Leading and Trailing follow the layout direction.

Result reporting

MessageBox::on_result takes impl Fn(MessageBoxResult, &mut EventContext) + 'static. The callback fires exactly once, whichever route closes the dialog — button activation, Escape, a press outside, or a programmatic dismissal — with MessageBoxResult::dismissal naming which one. On a button activation the modal is then closed by the framework; on the other routes it is already going away.

Accessibility

The widget exposes Role::AlertDialog, with set_modal(), set_live(Live::Assertive), set_name(title), and set_description(text + informative_text), so screen readers announce the dialog by its title as it opens and find the text as its description and by walking it. The ModalContainer that presents it publishes no dialog of its own around it, and the content under it is Live::Off, so the title is the one thing announced, once.

Density

The picture above is the widget at TargetDensity::Compact, the mouse-and-keyboard ladder. Below is the same subject on the same canvas with only the ladder changed, so what moves is the density and nothing else — where the subject no longer fits, that is what the denser targets cost it at that size. See docs/density-and-targets.md.

Touch

MessageBox at Touch density

API reference

📖 Full rustdoc API for this module

pub enum MessageBoxSeverity

Import: use teksilo::widgets::MessageBoxSeverity;

Alert severity level. Drives the icon glyph + tint shown beside the title, and (for Critical) whether click-outside dismiss is enabled.

#![allow(unused)]
fn main() {
pub enum MessageBoxSeverity { /* variants */ }
}

Variants

  • None — No icon. Use for plain notices where an icon would be noise.
  • Information — Informational notice — blue circle with "i" glyph.
  • Question — Confirmation prompt — accent-tinted circle with "?" glyph.
  • Warning — Non-fatal warning — amber triangle with "!" glyph.
  • Critical — Critical error — red circle with an "X" glyph. Click-outside dismissal is disabled (Escape still works).

pub enum ButtonRole

Import: use teksilo::widgets::ButtonRole;

Semantic role of a message-box button. Used for fallback escape resolution (Reject wins when no explicit escape button is set). Teksilo deliberately does not render Destructive buttons with a red fill — the dialog's severity icon and wording carry that signal. See crate::button for the framework-level rationale.

#![allow(unused)]
fn main() {
pub enum ButtonRole { /* variants */ }
}

Variants

  • Accept — Confirms / proceeds. Ok, Yes, Save, Open, Apply, Retry.
  • Reject — Bails out. Cancel, Close, No, Abort.
  • Destructive — Data-loss action. Discard. (Same visuals as Regular — the severity of the surrounding MessageBox carries the warning.)
  • Action — Side action. Help, Reset, RestoreDefaults, Ignore, and the "to all" variants.

pub enum StandardButton

Import: use teksilo::widgets::StandardButton;

The Qt-modeled catalog of standard buttons. Each variant resolves to a localized label, a semantic ButtonRole, and a stable intent-name string used internally for shortcut/action routing.

#![allow(unused)]
fn main() {
pub enum StandardButton { /* variants */ }
}

Variants

  • Ok — Accept / confirm. ButtonRole::Accept.
  • Cancel — Cancel the operation. ButtonRole::Reject.
  • Close — Close the dialog. ButtonRole::Reject.
  • Yes — Confirm with "Yes". ButtonRole::Accept.
  • No — Decline with "No". ButtonRole::Reject.
  • YesToAll — Confirm all remaining items. ButtonRole::Accept.
  • NoToAll — Decline all remaining items. ButtonRole::Reject.
  • Save — Save changes. ButtonRole::Accept.
  • SaveAll — Save all open items. ButtonRole::Accept.
  • Discard — Discard changes without saving. ButtonRole::Destructive.
  • Apply — Apply changes without closing. ButtonRole::Accept.
  • Reset — Reset to defaults. ButtonRole::Action.
  • RestoreDefaults — Restore factory defaults. ButtonRole::Action.
  • Abort — Abort the current operation. ButtonRole::Reject.
  • Retry — Retry the failed operation. ButtonRole::Accept.
  • Ignore — Ignore the error and continue. ButtonRole::Action.
  • Open — Open a file or resource. ButtonRole::Accept.
  • Help — Show help. ButtonRole::Action.

Methods

pub fn role(self) -> ButtonRole

The button's semantic role — used internally by MessageBox's escape-button fallback resolution, and available to callers that want to inspect a MessageBoxButton's role.

pub fn intent_name(self) -> &'static str

Stable string id used as both the shortcut id and the intent name for routing default/escape key activations. Scoped to a MessageBox instance via widget-scoped shortcut registration, so the same id is safe to reuse across instances.

pub fn default_label(self) -> LocalizedString

Default label for the button. Resolved through the Fluent catalog via tr_widget! so apps can override per-locale.

pub struct MessageBoxButton

Import: use teksilo::widgets::MessageBoxButton;

A single button placement inside a MessageBox, including an optional per-instance label override. Callers usually build these via From<StandardButton> (StandardButton::Ok.into()), or construct them manually when Custom is needed.

#![allow(unused)]
fn main() {
pub struct MessageBoxButton { /* fields */ }
}

Fields

  • kind: StandardButton — Which standard button this is — drives role, intent name, and (when label_override is None) the label.
  • label_override: Option<LocalizedString> — Optional explicit label that overrides kind.default_label(). Use sparingly: prefer translating the default via Fluent rather than hard-coding per-call labels.

Methods

pub fn standard(kind: StandardButton) -> Self

Build a button from a StandardButton with the default label.

pub fn label(mut self, label: impl Into<LocalizedString>) -> Self

Override the default translated label.

pub enum MessageBoxButtons

Import: use teksilo::widgets::MessageBoxButtons;

Pre-built button bundles covering the common MessageBox shapes. Custom combinations go through MessageBox::add_button or MessageBoxButtons::Custom.

#![allow(unused)]
fn main() {
pub enum MessageBoxButtons { /* variants */ }
}

Variants

  • Ok — Just Ok.
  • OkCancel — Ok + Cancel, Ok default, Cancel escape.
  • YesNo — Yes + No. No is the default, and No is the escape. See the module docs for why the default is the negative answer.
  • YesNoCancel — Yes + No + Cancel. No is the default, Cancel is the escape — Enter takes the safe answer to the question asked, Escape leaves the dialog.
  • SaveDiscardCancel — The unsaved-changes triad: Save + Discard + Cancel.
  • RetryIgnoreAbort — The error-recovery triad: Retry + Ignore + Abort.
  • Custom (Vec<MessageBoxButton>) — Explicit list. MessageBox preserves the order as the visual button order (leading Spacer pushes all buttons to the trailing edge; default button may appear anywhere).

pub enum MessageBoxDismissal

Import: use teksilo::widgets::MessageBoxDismissal;

How a MessageBox came to close.

This replaced a dismissed_by_escape: bool whose own rustdoc claimed to cover scrim-click as well — a contract no code path could produce, because the only writer was the Escape action. One field that names the route cannot drift from its documentation the way two overlapping booleans can, and the caller can finally tell "the user chose Cancel" from "the user waved the dialog away", which for a Save/Discard/Cancel prompt are different answers.

#![allow(unused)]
fn main() {
pub enum MessageBoxDismissal { /* variants */ }
}

Variants

  • Button — A button was chosen: clicked, or Enter on the default.
  • Escape — Escape, resolved to the escape button.
  • ClickOutside — A press outside the dialog, where its ModalCloseBehavior permits it.
  • Programmatic — It went away for another reason — the application dismissed it, or an enclosing surface closed and took it along. button still carries the escape-button resolution, because something has to be reported and that is the same answer Escape would have given.

pub struct MessageBoxResult

Import: use teksilo::widgets::MessageBoxResult;

Report passed to MessageBox::on_result when the dialog closes.

#![allow(unused)]
fn main() {
pub struct MessageBoxResult { /* fields */ }
}

Fields

  • button: StandardButton — Which button fired — either by click, Enter (the focused button, else the default), or escape-button resolution for any of the dismissal routes.
  • checkbox_checked: bool — State of the "Don't show again" checkbox at dismiss time, when one was configured via MessageBox::show_again_checkbox or MessageBox::show_again_checkbox_state. false when no checkbox was attached.
  • dismissal: MessageBoxDismissal — Which route closed the dialog.

Methods

pub fn was_dismissed(&self) -> bool

Whether the dialog went away without the user choosing a button.

The predicate the old dismissed_by_escape flag was reached for, minus the claim that Escape was the only way to get there.

pub struct MessageBox

Import: use teksilo::widgets::MessageBox;

A modal alert dialog that displays a severity icon, title, body text, and one or more buttons.

Constructed via severity-named constructors (MessageBox::information, MessageBox::warning, MessageBox::critical, MessageBox::question, MessageBox::plain), configured fluently, and presented with MessageBox::present. See the module documentation for the full guide.

#![allow(unused)]
fn main() {
pub struct MessageBox { /* fields */ }
}

Methods

pub fn information(title: impl Into<LocalizedString>) -> Self

Construct an informational MessageBox (Information severity).

pub fn warning(title: impl Into<LocalizedString>) -> Self

Construct a warning MessageBox (Warning severity).

pub fn critical(title: impl Into<LocalizedString>) -> Self

Construct a critical-error MessageBox (Critical severity). Click-outside dismissal is disabled; use an explicit button or Escape to close.

pub fn question(title: impl Into<LocalizedString>) -> Self

Construct a confirmation / question MessageBox (Question severity).

pub fn plain(title: impl Into<LocalizedString>) -> Self

Construct a plain MessageBox with no severity icon.

pub fn text(mut self, text: impl Into<LocalizedString>) -> Self

Primary message line, rendered in typography.body with text_primary. Prefer a short, self-contained sentence — details belong in informative_text.

pub fn informative_text(mut self, text: impl Into<LocalizedString>) -> Self

Secondary, explanatory text rendered below the primary text in typography.body with text_secondary. Matches Qt's setInformativeText.

pub fn detailed_text(mut self, text: impl Into<LocalizedString>) -> Self

Detailed text hidden behind a "Show details" Accordion — for technical diagnostics (stack traces, error codes). Matches Qt's setDetailedText.

pub fn buttons(mut self, preset: MessageBoxButtons) -> Self

Apply a preset button bundle. Implicitly sets default and escape buttons for the preset (both can be overridden via MessageBox::default_button and MessageBox::escape_button).

pub fn add_button(mut self, button: impl Into<MessageBoxButton>) -> Self

Append a single button. Use to augment a preset (rare) or to build a bespoke button row without going through MessageBoxButtons::Custom.

pub fn add_buttons( self, buttons: impl IntoIterator<Item = impl Into<MessageBoxButton>>, ) -> Self

Append several buttons from an iterator, in order.

The loop form of add_button, for a bespoke button row built from data rather than spelled out one call at a time.

pub fn default_button(mut self, which: StandardButton) -> Self

Mark which button activates on Enter and receives initial focus. Must refer to one of the buttons configured via buttons / add_button.

pub fn escape_button(mut self, which: StandardButton) -> Self

Mark which button activates on Escape (and scrim-click, when allowed). Must refer to one of the configured buttons.

pub fn show_again_checkbox(mut self, label: impl Into<LocalizedString>) -> Self

Attach a "Don't show again"-style checkbox below the body. Internally creates a Signal<bool> initialized to false and reports its state in MessageBoxResult::checkbox_checked. For external observation, use MessageBox::show_again_checkbox_state instead.

pub fn show_again_checkbox_state(mut self, signal: Signal<bool>) -> Self

Like MessageBox::show_again_checkbox, but with a caller-owned Signal<bool> so the checkbox state survives the dialog lifetime (useful for "remember my choice" persistence).

pub fn title_alignment(mut self, alignment: HAlignment) -> Self

Where the title sits in the header's text column. Default HAlignment::Leading. Center matches a macOS alert; Windows and GNOME keep the title leading. Leading / Trailing follow the layout direction, so they mirror in right-to-left locales.

pub fn button_alignment(mut self, alignment: HAlignment) -> Self

Where the button row sits along the bottom of the dialog. Default HAlignment::Trailing. Center matches a macOS alert; Leading packs the buttons at the start edge. Leading / Trailing follow the layout direction, so they mirror in right-to-left locales.

pub fn on_result(mut self, f: impl Fn(MessageBoxResult, &mut EventContext) + 'static) -> Self

Register the result callback, invoked exactly once however the dialog closes — a button (by click, or by the Enter/Escape shortcut), a press outside, or a programmatic dismissal.

pub fn present(mut self, ctx: &mut EventContext)

Present the MessageBox as a modal on top of ctx's current tree. Consumes self; callers who need to present multiple dialogs with shared config should build a factory closure.

pub trait EventContextMessageBoxExt

Import: use teksilo::widgets::EventContextMessageBoxExt;

Extension trait on EventContext for ergonomic MessageBox presentation. Mirrors ctx.present_modal(...) for the general case.

#![allow(unused)]
fn main() {
pub trait EventContextMessageBoxExt { /* associated items below */ }
}

Associated items

fn present_message_box(&mut self, mb: MessageBox);

Present mb as a modal. Equivalent to mb.present(self).