Skip to content

SystemTrayIcon

Use the SystemTrayIcon element to add an icon and menu to the desktop’s system tray, also known as the notification area, status area, or menu bar extras, depending on the platform.

SystemTrayIcon is a top-level component: derive your own component from it with inherits SystemTrayIcon instead of placing it inside a Window. A SystemTrayIcon component has no window of its own — the icon lives in the tray, and the only UI it presents is the menu.

export component ExampleTray inherits SystemTrayIcon {
icon: @image-url("tray-icon.png");
tooltip: "My App";
Menu {
MenuItem {
title: "Quit";
activated => { quit(); }
}
}
callback quit();
}
slint

Create the component from your language binding as you would any other Slint component; the tray icon appears as soon as the instance is created and an event loop is running, and disappears when the instance is dropped.

image default: the empty image

The icon shown in the system tray. The image is scaled by the platform to the size expected for tray icons. Use @image-url(...) to embed an icon asset, or bind to an image property fed from your code. The tray icon is only created once a non-empty image has been assigned.

string default: ""

The hover text shown over the tray icon. Typically the application name or a short status message.

bool default: true

Whether the tray icon is registered with the OS. Set it to false to hide the icon without dropping the component instance, and back to true to show it again. The show() and hide() methods on the language-binding side are convenience aliases that set this property.

string default: ""

A descriptive name for the tray entry, separate from the hover tooltip. Where it actually shows up depends on the platform:

PlatformWhere title appears
Linux, *BSDUsed by accessibility tools and shown by some desktops when listing tray icons (e.g. an overflow menu). Set as the StatusNotifierItem Title property.
macOSThe visible text label rendered next to the icon in the menu bar (think battery percent, clock).
WindowsHas no visible effect; the notification area renders only the icon.

Invoked when the user activates the tray icon itself, as opposed to picking an entry from its menu. What counts as activation, and whether it’s invoked at all, depends on the platform:

PlatformActivation behavior
Linux, *BSDInvoked on a left-click of the icon. The exact gesture is decided by the desktop environment or shell extension hosting the tray.
macOSInvoked on a click when no Menu is attached (or when an if cond : Menu { ... }’s condition is currently false). When a populated menu is attached, AppKit pops it open instead and activated doesn’t fire.
WindowsInvoked on a left-click of the icon. Right-click opens the menu.

The child Menu defines the menu that is shown when the user clicks or right-clicks the tray icon. Its structure is the same as for MenuBar and ContextMenuArea: use MenuItem for entries, nested Menu elements for sub-menus, and MenuSeparator for separators. See Menu for the properties and callbacks available on those elements.

The menu tree is reactive: when any property the menu reads changes (for example the title, enabled, or checked binding of a MenuItem), Slint rebuilds the platform menu so the tray reflects the new state on its next open.

Keyboard shortcut bindings on MenuItems within a SystemTrayIcon are ignored — tray menus are not attached to a focused window, so there is nothing for the shortcut to fire against.

The generated public API for a SystemTrayIcon-rooted component is smaller than the one for a Window-rooted component. Construction, property and callback accessors, and global access work the same way. Two things are missing:

OperationWindow-rootedSystemTrayIcon-rooted
access the windowyesno
run the event loopyesno

show and hide exist on both, but on a SystemTrayIcon they set the visible property, and the platform backend translates that into the native tray API. A visible SystemTrayIcon keeps the event loop alive the same way a visible window does.

A typical app instantiates both a main window and a tray, shows them, and runs the event loop. The snippets below also wire the built-in activated callback so a click on the tray icon brings the window back if the user has hidden it.

fn main() -> Result<(), slint::PlatformError> {
let window = MainWindow::new()?;
let tray = ExampleTray::new()?;
let window_weak = window.as_weak();
tray.on_activated(move || {
if let Some(w) = window_weak.upgrade() {
let _ = w.show();
}
});
window.show()?;
tray.show()?;
slint::run_event_loop()
}
rust

A program that exposes only a SystemTrayIcon and no window is also valid: skip the MainWindow instance, and the loop quits once the tray is hidden (or slint::quit_event_loop is called). No WindowAdapter is created in that case — the platform backend is still selected the usual way, but no window opens.

PlatformMechanism
Linux, *BSDStatusNotifierItem / AppIndicator on D-Bus
macOSNSStatusItem in the menu bar
WindowsShell notification area icon (Shell_NotifyIcon)

On Linux, a desktop environment or shell extension that implements the StatusNotifierItem specification is required; plain X11 system trays are not supported. GNOME, for example, needs an extension such as AppIndicator and KStatusNotifierItem Support.


© 2026 SixtyFPS GmbH