Slint Kit Documentation

Navigation

Notification Center for Slint

KitNotificationCenter · Slint Kit 0.3.1

Notification list with preview, read and removal actions by stable identity.

Notification list with preview, read and removal actions by stable identity.
Native app built from the example below.

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.

Open a preview, mark an item read, or dismiss it. Rust owns each notice’s stable key and read state.

ui/app.slint

export { KitFormValidation, HtmlInputKind, NumberInputFormat, KitInputConstraints, KitValidationResult, KitValidityState } from "@kit/kit.slint";
// SPDX-License-Identifier: GPL-3.0-or-later
import { KitNotificationCenter, NotificationRow, KitTheme, KitThemes } from "@kit/kit.slint";
export component App inherits Window {
    title: "KitNotificationCenter 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 <[NotificationRow]> notices;
    in property <string> result: "Choose a notification";
    callback open-notice(int, int);
    callback mark-read(int, int);
    callback dismiss-notice(int, int);
    VerticalLayout {
        padding: 24px;
        spacing: 16px;
        alignment: start;
        control := KitNotificationCenter {
            theme: root.theme; rows: root.notices; height: 320px;
            activate(token, generation) => { root.open-notice(token, generation); }
            mark-read(token, generation) => { root.mark-read(token, generation); }
            dismiss-row(token, generation) => { root.dismiss-notice(token, generation); }
        }
        result := Text { text: root.result; color: root.theme.text-primary; }
    }

}

src/main.rs

// SPDX-License-Identifier: GPL-3.0-or-later
use slint::{ComponentHandle, ModelRc, VecModel};
use std::{cell::RefCell, rc::Rc};
mod ui { slint::include_modules!(); }
#[derive(Clone, Copy, PartialEq, Eq)]
enum Notice { SharedDocument, ExportReady }
impl Notice {
    fn token(self) -> i32 { match self { Self::SharedDocument => 11, Self::ExportReady => 23 } }
    fn label(self) -> &'static str { match self { Self::SharedDocument => "Document shared", Self::ExportReady => "Export ready" } }
}
fn publish(app: &ui::App, notices: &[(Notice, bool)]) {
    app.set_notices(ModelRc::new(VecModel::from(notices.iter().map(|(key, read)| ui::NotificationRow {
        item: ui::OptionRow { token: key.token(), generation: 1, label: key.label().into(), description: "Review the latest project update.".into(), disabled: false }, read: *read,
    }).collect::<Vec<_>>())));
}
fn main() -> Result<(), slint::PlatformError> {
    let app = ui::App::new()?;
    slint_kit::init_form_validation!(ui, app);
    let notices = Rc::new(RefCell::new(vec![(Notice::SharedDocument, false), (Notice::ExportReady, false)]));
    publish(&app, &notices.borrow());
    let weak = app.as_weak(); let state = notices.clone();
    app.on_open_notice(move |token, generation| {
        if generation != 1 { return; }
        let label = state.borrow().iter().find(|(key, _)| key.token() == token).map(|(key, _)| key.label());
        if let (Some(app), Some(label)) = (weak.upgrade(), label) { app.set_result(format!("Preview: {label}").into()); }
    });
    let weak = app.as_weak(); let state = notices.clone();
    app.on_mark_read(move |token, generation| { if generation != 1 { return; } if let Some(app) = weak.upgrade() {
        if let Some((_, read)) = state.borrow_mut().iter_mut().find(|(key, _)| key.token() == token) { *read = true; }
        let snapshot = state.borrow().clone(); publish(&app, &snapshot); app.set_result("Notification marked read".into());
    } });
    let weak = app.as_weak();
    app.on_dismiss_notice(move |token, generation| { if generation != 1 { return; } if let Some(app) = weak.upgrade() {
        notices.borrow_mut().retain(|(key, _)| key.token() != token);
        let snapshot = notices.borrow().clone(); publish(&app, &snapshot); app.set_result("Notification dismissed".into());
    } });
    app.run()
}

Cargo.toml and build.rs

Cargo.toml

[package]
name = "slint-kit-notification-center-example"
version = "0.1.0"
edition = "2024"
rust-version = "1.92"
license = "GPL-3.0-or-later"
publish = false

[dependencies]
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

Supply NotificationRow values and acknowledge activate, mark-read and dismiss-row by token and generation. Keep popup placement and mark-read-label and read-label stable during an open session.

Removal disables actions and emits the request after a 150 ms fade, omitted with reduced motion; changing identity cancels pending removal. Large collections use a virtualized list, and focus-token with focus-request can focus a preview.

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
Notification list with preview, read and removal actions by stable identity.
Native screenshot of the same example, rendered with Skia.
// SPDX-License-Identifier: GPL-3.0-or-later
import { KitNotificationCenter, KitTheme, KitThemes } from "@kit/kit.slint";

export component Example inherits Window {
    title: "KitNotificationCenter example";
    preferred-width: 620px;
    preferred-height: 440px;
    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: "Notification Center"; color: root.theme.text-primary; font-size: 20px * root.theme.text-scale; font-weight: 600; }
        KitNotificationCenter { theme: root.theme; height: 300px; rows: [{ item: { token: 11, generation: 1, label: "Jamie shared a document", description: "Research notes are ready for review.", disabled: false }, read: false }, { item: { token: 23, generation: 1, label: "Your export is ready", description: "Download the latest project archive.", disabled: false }, read: true }]; }
        if root.status != "": Text { text: root.status; color: root.theme.text-secondary; font-size: 12px * root.theme.text-scale; wrap: word-wrap; }
    }
}

Download this example

Public API

Inherits Rectangle.

Properties

Name Type Direction
theme KitTheme in
control-size ControlSize in
rows [NotificationRow] in
focus-token int in
focus-request int in
empty-label string in
empty-description string in
open-label string in
mark-read-label string in
read-label string in
dismiss-label string in
disabled bool in
content-height length out

Types and variants

Type Declaration
enum ControlSize compact, medium, comfortable
struct NotificationRow item: OptionRow, read: bool
struct OptionRow token: int, generation: int, label: string, description: string, disabled: bool

Callbacks

See also