Adding a System Tray Icon with Context Menu in Tauri v1.2+
Add a system tray icon with a context menu to a Tauri v1.2+ app so users can show the window, open settings, or quit without restoring the main UI.
13 Jun 2026, 14:35 UTC

Problem Overview
You want a Tauri desktop application to stay accessible even when its main window is hidden. A system tray (notification area) icon with a right-click context menu lets users show the window, open settings, or quit the app without restoring the UI.
Prerequisites
- Tauri project version
>=1.2.0(the unified tray API was introduced in this release). tauricrate with thesystem-trayandmenufeatures enabled inCargo.toml.- A Rust toolchain configured for the target desktop platform (Windows, macOS, or Linux).
- The Tauri CLI (
cargo tauri) installed globally or viacargo install tauri-cli.
Step-by-Step Implementation
1. Enable required features
Open src-tauri/Cargo.toml and ensure the [dependencies.tauri] section includes the features:
tauri = { version = "1.2", features = ["system-tray", "menu"] }
2. Prepare an icon
Place a small PNG (recommended 16x16 or 32x32 pixels) in src-tauri/icons/tray.png. The icon must be a valid image; Tauri will load it at runtime.
3. Create and register the tray icon
In src-tauri/src/main.rs, add the tray builder inside the tauri::Builder::default().setup callback. Building the menu inside setup gives you access to the AppHandle, which MenuItem::new requires:
use tauri::menu::{Menu, MenuItem};
use tauri::tray::TrayIconBuilder;
use tauri::Manager;
tauri::Builder::default()
.setup(|app| {
// Load the icon bytes from the bundled resource
let icon_bytes = include_bytes!("../icons/tray.png");
let icon = tauri::Icon::from_bytes(icon_bytes)?;
// Build the menu with access to the app handle
let menu = Menu::new()
.add_item(&MenuItem::new(app, "show", "Show", true, None)?)
.add_item(&MenuItem::new(app, "settings", "Settings", true, None)?)
.add_item(&MenuItem::new(app, "quit", "Quit", true, None)?);
// Create the tray icon and attach the menu
let _tray = TrayIconBuilder::new()
.icon(icon)
.menu(&menu)
.on_menu_event(|app, event| match event.id.as_ref() {
"show" => {
if let Some(window) = app.get_window("main") {
let _ = window.show();
}
}
"settings" => {
// Example: open a settings dialog or window
println!("Settings requested");
}
"quit" => {
app.exit(0);
}
_ => {}
})
.build(app)?;
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
Key parts:
Icon::from_bytesloads the PNG directly from the compiled binary.MenuItem::newcreates each entry with an ID, a display label, an enabled flag, and an optional accelerator.- The
on_menu_eventclosure matches onevent.id(the string you gave each item) to perform actions: show the main window, handle settings, or quit.
4. Build and run
From the project root, execute:
# Development mode (hot reload)
cargo tauri dev
# Production build
cargo tauri build
No special permissions are required beyond the ability to read the source files and write to the src-tauri/target directory.
Expected Checks
- After running
cargo tauri dev, look for the tray icon in the system notification area (Windows taskbar, macOS menu bar, or Linux status notifier). - Right-click the icon; a menu with Show, Settings, and Quit should appear.
- Selecting Show restores the main window if it was hidden.
- Selecting Quit terminates the process without error messages in the console.
- Repeat the same checks with the production binary produced by
cargo tauri buildto confirm the feature works outside the dev environment.
Troubleshooting and Recovery Options
- Icon does not appear
- Verify that
system-trayandmenufeatures are present inCargo.toml. - Confirm the icon file is a valid PNG or ICO and that the path in
include_bytes!matches the actual location. - On Linux, some desktop environments (e.g., GNOME Shell without a status icon extension) hide legacy system trays. Install a status notifier extension or test on an environment that supports trays (e.g., KDE, XFCE).
- Run
cargo cleanthen rebuild to eliminate stale artifacts.
- Verify that
- Menu items trigger no action
- Ensure the
event.idstrings in theon_menu_eventmatch exactly the IDs you passed toMenuItem::new(case-sensitive). - Check the console for panic messages; a common mistake is forgetting to handle the
ResultfromTrayIconBuilder::build.
- Ensure the
- Application fails to compile or crashes on startup
- Verify that the Tauri version you are using is >=1.2.0; older versions require the deprecated
tauri::api::tray::TrayIconBuilderAPI. - Ensure the
tauricrate is compiled with thesystem-trayfeature; missing features cause build errors.
- Verify that the Tauri version you are using is >=1.2.0; older versions require the deprecated
Limitations
The tray API is stable in Tauri 1.2+, but the underlying system tray behavior varies by OS:
- Windows and macOS provide a consistent notification area.
- On Linux, the icon relies on the
StatusNotifierItemspecification; desktops that do not implement it will not show the icon. - The API does not support dynamic icon changes at runtime without rebuilding the tray; if you need animated trays, consider a custom native module.
To verify that your target Linux distribution supports the tray, run a simple test application that uses gtk-status-icon or appindicator and confirm the icon appears.
Summary
By enabling the system-tray and menu features, defining a Menu with MenuItem entries, and attaching it to a TrayIconBuilder within the Tauri setup hook, you obtain a functional system tray icon that lets users show the window, open settings, or quit the application. Verify the icon and menu in both development and production builds, and use the troubleshooting steps above if the tray does not appear as expected.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.