Toast Host for Slint
KitToastHost · Slint Kit 0.3.0
Transient notification stack supplied by a Rust-owned queue.

Try the component
Download the complete project, extract it and run cargo run --locked in its folder. Rust 1.92+; Slint Kit 0.3.0 from crates.io. You can also copy the four files below.
Show an archive notice, Undo its action, or dismiss it. This example keeps notices until an explicit action.
ui/app.slint
export { KitFormValidation, HtmlInputKind, NumberInputFormat, KitInputConstraints, KitValidationResult, KitValidityState } from "@kit/kit.slint";
// SPDX-License-Identifier: GPL-3.0-or-later
import { KitToastHost, KitButton, ToastEntry, ToastInteraction, AlertSeverity, KitTheme, KitThemes } from "@kit/kit.slint";
export component App inherits Window {
title: "KitToastHost example";
preferred-width: 520px;
preferred-height: 420px;
max-width: 100000px;
max-height: 100000px;
background: root.theme.canvas;
in-out property <KitTheme> theme: KitThemes.light;
in property <[ToastEntry]> entries;
in property <string> result: "Project archived";
callback undo(int);
callback dismiss-toast(int);
callback interaction(int, ToastInteraction, bool);
callback add();
VerticalLayout {
padding: 24px;
spacing: 16px;
alignment: start;
KitButton { theme: root.theme; text: "Show archive notice"; activated => { root.add(); } }
control := KitToastHost { theme: root.theme; entries: root.entries; action(token) => { root.undo(token); } dismiss(token) => { root.dismiss-toast(token); } interaction(token, source, engaged) => { root.interaction(token, source, engaged); } }
result := Text { text: root.result; color: root.theme.text-primary; }
}
}
src/main.rs
// SPDX-License-Identifier: GPL-3.0-or-later
use web_time::Instant;
use slint::{ComponentHandle, ModelRc, VecModel};
use slint_kit::{ToastQueue, ToastLifetime, ToastPause};
use std::{cell::RefCell, rc::Rc, num::NonZeroUsize};
mod ui { slint::include_modules!(); }
fn publish(app: &ui::App, queue: &ToastQueue<()>) {
let entries = queue.entries().map(|entry| ui::ToastEntry { token: i32::try_from(entry.id.get()).expect("view token capacity"), title: "Project archived".into(), message: "Your project can be restored.".into(), action_label: "Undo".into(), severity: ui::AlertSeverity::Success, dismissible: true }).collect::<Vec<_>>();
app.set_entries(ModelRc::new(VecModel::from(entries)));
}
fn main() -> Result<(), slint::PlatformError> {
let app = ui::App::new()?;
slint_kit::init_form_validation!(ui, app);
let epoch = Instant::now();
let queue = Rc::new(RefCell::new(ToastQueue::new(NonZeroUsize::new(3).unwrap())));
queue.borrow_mut().push((), ToastLifetime::Persistent, epoch.elapsed()).expect("toast identity");
publish(&app, &queue.borrow());
let state = queue.clone(); let weak = app.as_weak();
app.on_add(move || { state.borrow_mut().push((), ToastLifetime::Persistent, epoch.elapsed()).expect("toast identity"); if let Some(app) = weak.upgrade() { publish(&app, &state.borrow()); app.set_result("Project archived".into()); } });
let state = queue.clone(); let weak = app.as_weak();
app.on_undo(move |token| {
let id = state.borrow().entries().find(|entry| i32::try_from(entry.id.get()).ok() == Some(token)).map(|entry| entry.id);
if let Some(id) = id { state.borrow_mut().remove(id); if let Some(app) = weak.upgrade() { publish(&app, &state.borrow()); app.set_result("Archive undone".into()); } }
});
let state = queue.clone(); let weak = app.as_weak();
app.on_dismiss_toast(move |token| {
let id = state.borrow().entries().find(|entry| i32::try_from(entry.id.get()).ok() == Some(token)).map(|entry| entry.id);
if let Some(id) = id { state.borrow_mut().remove(id); if let Some(app) = weak.upgrade() { publish(&app, &state.borrow()); app.set_result("Toast dismissed".into()); } }
});
app.on_interaction(move |token, source, engaged| {
let id = queue.borrow().entries().find(|entry| i32::try_from(entry.id.get()).ok() == Some(token)).map(|entry| entry.id);
if let Some(id) = id { queue.borrow_mut().set_paused(id, match source { ui::ToastInteraction::Pointer => ToastPause::Pointer, ui::ToastInteraction::Focus => ToastPause::Focus }, engaged, epoch.elapsed()); }
});
app.run()
}
Cargo.toml and build.rs
Cargo.toml
[package]
name = "slint-kit-toast-host-example"
version = "0.1.0"
edition = "2024"
rust-version = "1.92"
license = "GPL-3.0-or-later"
publish = false
[dependencies]
web-time = "=1.1.0"
slint-kit = "=0.3.0"
slint = { version = "=1.18.1", default-features = false, features = ["std", "compat-1-18", "backend-winit", "renderer-skia", "accessibility"] }
[build-dependencies]
slint-kit-build = "=0.3.0"
[workspace]
build.rs
fn main() { slint_kit_build::compile("ui/app.slint").expect("compile component example"); }
Files: Cargo.toml · build.rs · ui/app.slint · src/main.rs
Project ToastQueue entries through entries and forward action, dismissal and interaction callbacks. Place the stack in a window region appropriate for your application.
Each entry is rendered by KitToast without a per-delegate timer. The owner decides lifetime, ordering and removal while preserving remaining time after a pause.
Visual composition
The file below produces the screenshot. For controller-driven components, it shows the displayed state without supplying the Rust wiring. Create a project.
Show the screenshot source

// SPDX-License-Identifier: GPL-3.0-or-later
import { AlertSeverity, KitTheme, KitThemes, KitToastHost } from "@kit/kit.slint";
export component Example inherits Window {
title: "KitToastHost example";
preferred-width: 480px;
preferred-height: 390px;
max-width: 100000px;
max-height: 100000px;
background: root.theme.canvas;
in-out property <KitTheme> theme: KitThemes.light;
in-out property <string> status;
VerticalLayout {
padding: 24px; spacing: 16px; alignment: start;
Text { text: "Toast Host"; color: root.theme.text-primary; font-size: 20px * root.theme.text-scale; font-weight: 600; }
KitToastHost { theme: root.theme; entries: [{ token: 11, title: "Project archived", message: "Your notes are safely stored.", action-label: "Undo", severity: AlertSeverity.success, dismissible: true }, { token: 23, title: "Invite sent", message: "Jamie can now join the workspace.", action-label: "", severity: AlertSeverity.information, dismissible: true }]; }
if root.status != "": Text { text: root.status; color: root.theme.text-secondary; font-size: 12px * root.theme.text-scale; wrap: word-wrap; }
}
}
Public API
Inherits VerticalLayout.
Properties
| Name | Type | Direction |
|---|---|---|
theme |
KitTheme |
in |
entries |
[ToastEntry] |
in |
Types and variants
| Type | Declaration |
|---|---|
enum AlertSeverity |
information, success, warning, error |
struct ToastEntry |
token: int, title: string, message: string, action-label: string, severity: AlertSeverity, dismissible: bool |
enum ToastInteraction |
pointer, focus |
Callbacks
action(int)dismiss(int)interaction(int,ToastInteraction,bool)