Slint Kit Documentation

Navigation

Drawer for Slint

KitDrawer · Slint Kit 0.3.0

Side modal panel bounded by its host window’s width.

Side modal panel bounded by its host window’s width.
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 project details, archive the project, or dismiss with Escape. Closing restores the opener’s focus.

ui/app.slint

export { KitFormValidation, HtmlInputKind, NumberInputFormat, KitInputConstraints, KitValidationResult, KitValidityState } from "@kit/kit.slint";
// SPDX-License-Identifier: GPL-3.0-or-later
import { KitDrawer, KitDialogPanel, KitButton, DialogTabPolicy, CloseReason, KitTheme, KitThemes } from "@kit/kit.slint";
export component App inherits Window {
    title: "KitDrawer example";
    preferred-width: 520px;
    preferred-height: 400px;
    max-width: 100000px;
    max-height: 100000px;
    background: root.theme.canvas;
    in-out property <KitTheme> theme: KitThemes.light;
    in property <bool> showing;
    in property <string> result: "Project active";
    callback open();
    callback close(CloseReason);
    callback archive();
    public function focus-opener() { opener.take-focus(); }
    public function focus-dialog() { drawer.take-focus(); }

    VerticalLayout {
        padding: 24px;
        spacing: 16px;
        alignment: start;
        opener := KitButton { theme: root.theme; text: "Open project details"; disabled: root.showing; activated => { root.open(); } }
        Text { text: root.result; color: root.theme.text-primary; }

    }
    drawer := KitDrawer {
        theme: root.theme; title: "Project details"; width: root.width; height: root.height;
        state: { open: root.showing, topmost: root.showing, busy: false };
        tab-policy: DialogTabPolicy.native;
        dismiss(reason) => { root.close(reason); }
        restore-focus => { root.focus-opener(); }
            Text { text: "Archive this project?"; color: root.theme.text-primary; font-size: 20px * root.theme.text-scale; wrap: word-wrap; }
            archive-button := KitButton { theme: root.theme; text: "Archive project"; activated => { root.archive(); } }
    }
}

src/main.rs

// SPDX-License-Identifier: GPL-3.0-or-later
use slint::ComponentHandle;
use slint_kit::{OverlayStack, OverlaySpec, OverlayId, DismissReason, CloseResult};
mod ui { slint::include_modules!(); }
fn main() -> Result<(), slint::PlatformError> {
    let app = ui::App::new()?;
    slint_kit::init_form_validation!(ui, app);
    let overlays = std::rc::Rc::new(std::cell::RefCell::new(OverlayStack::new()));
    let weak = app.as_weak();
    let stack = overlays.clone();
    app.on_open(move || {
        if let Some(app) = weak.upgrade() {
            if stack.borrow().is_empty() {
                stack.borrow_mut().push(OverlaySpec::new(OverlayId(1), None, true)).expect("single modal");
                app.set_showing(true);
                app.invoke_focus_dialog();
            }
        }
    });
    let weak = app.as_weak();
    let stack = overlays.clone();
    app.on_close(move |reason| {
        let reason = match reason {
            ui::CloseReason::Escape => DismissReason::Escape,
            ui::CloseReason::OutsidePress => DismissReason::OutsidePress,
            ui::CloseReason::SystemBack => DismissReason::SystemBack,
            ui::CloseReason::TriggerToggle => DismissReason::TriggerToggle,
            ui::CloseReason::Programmatic => DismissReason::Programmatic,
            ui::CloseReason::HostClosed => DismissReason::HostClosed,
        };
        let closed = matches!(stack.borrow_mut().request_close(reason), CloseResult::Closed(_));
        if closed { if let Some(app) = weak.upgrade() { app.set_showing(false); app.invoke_focus_opener(); } }
    });
    let weak = app.as_weak();
    app.on_archive(move || { if let Some(app) = weak.upgrade() { app.set_result("Project archived".into()); app.invoke_close(ui::CloseReason::Programmatic); } });
    app.run()
}

Cargo.toml and build.rs

Cargo.toml

[package]
name = "slint-kit-drawer-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

Mount it at the window root after scrolling content and give it the full viewport. Connect inherited dismiss and focus-next, then restore-focus, to the modal stack and focus registry.

The panel anchors to the trailing edge and bounds panel-width by available width. Opening focuses Close; the host must register fields and restore the exact opener on closure.

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
Side modal panel bounded by its host window’s width.
Native screenshot of the same example, rendered with Skia.
// SPDX-License-Identifier: GPL-3.0-or-later
import { KitButton, KitDrawer, KitTextField, KitTheme, KitThemes } from "@kit/kit.slint";

export component Example inherits Window {
    title: "KitDrawer example";
    preferred-width: 560px;
    preferred-height: 420px;
    max-width: 100000px;
    max-height: 100000px;
    background: root.theme.canvas;
    in-out property <KitTheme> theme: KitThemes.light;
    in-out property <string> status;
    KitDrawer { theme: root.theme; panel-width: 380px * root.theme.text-scale; width: parent.width; height: parent.height; title: "Project details"; state: { open: true, topmost: true, busy: false }; Text { text: "Field notes"; color: root.theme.text-primary; font-size: 14px * root.theme.text-scale; wrap: word-wrap; vertical-stretch: 0; }KitTextField { theme: root.theme; label: "Project name"; text: "Field notes"; }KitButton { theme: root.theme; text: "Save changes"; activated => { root.status = "Action requested"; } } if root.status != "": Text { text: root.status; color: root.theme.text-secondary; font-size: 12px * root.theme.text-scale; wrap: word-wrap; vertical-stretch: 0; } }
}

Download this example

Public API

Inherits KitDialogSurface.

Properties

Name Type Direction
control-size ControlSize in
title string in
close-label string in
panel-width length in
Available inherited properties
Name Type Defined on
theme KitTheme KitDialogSurface
state DialogState KitDialogSurface
dismiss-on-backdrop bool KitDialogSurface
tab-policy DialogTabPolicy KitDialogSurface

Types and variants

Type Declaration
enum ControlSize compact, medium, comfortable

Callbacks

Functions

See also