This guide details the implementation of a tray icon in a Tauri application, including customizing the icon, creating menu items, and handling events. The steps also include dynamically switching the tray icon based on themes.
Dependencies
Add the required dependencies in src-tauri/Cargo.toml
:
[dependencies]
tauri = { version = "2.0.6", features = ["tray-icon", "image-png"] }
Tray Icon Setup
Function: enable_tray
fn enable_tray(app: &mut tauri::App) {
use tauri::{
image::Image,
menu::{MenuBuilder, MenuItem},
tray::TrayIconBuilder,
};
// Create menu items
let quit_i = MenuItem::with_id(app, "quit", "Quit Coco", true, None::<&str>).unwrap();
let settings_i = MenuItem::with_id(app, "settings", "Settings...", true, None::<&str>).unwrap();
let open_i = MenuItem::with_id(app, "open", "Open Coco", true, None::<&str>).unwrap();
let about_i = MenuItem::with_id(app, "about", "About Coco", true, None::<&str>).unwrap();
let hide_i = MenuItem::with_id(app, "hide", "Hide Coco", true, None::<&str>).unwrap();
// Build menu
let menu = MenuBuilder::new(app)
.item(&open_i)
.separator()
.item(&hide_i)
.item(&about_i)
.item(&settings_i)
.separator()
.item(&quit_i)
.build()
.unwrap();
// Create tray icon
let _tray = TrayIconBuilder::with_id("tray")
.icon(Image::from_bytes(include_bytes!("../icons/light@2x.png")).expect("Failed to load icon"))
.menu(&menu)
.on_menu_event(|app, event| match event.id.as_ref() {
"open" => handle_open_coco(app),
"hide" => handle_hide_coco(app),
"about" => { let _ = app.emit("open_settings", "about"); },
"settings" => { let _ = app.emit("open_settings", ""); },
"quit" => app.exit(0),
_ => println!("Unhandled menu item: {:?}", event.id),
})
.build(app)
.unwrap();
}
Register Tray Function in run
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let mut ctx = tauri::generate_context!();
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![switch_tray_icon])
.setup(|app| {
init(app.app_handle());
enable_tray(app); // Register tray events
Ok(())
})
.run(ctx)
.expect("Error while running Tauri application");
}
Dynamically Switch Tray Icon
Rust Command: switch_tray_icon
#[tauri::command]
fn switch_tray_icon(app: tauri::AppHandle, is_dark_mode: bool) {
println!("is_dark_mode: {}", is_dark_mode);
const DARK_ICON_PATH: &[u8] = include_bytes!("../icons/dark@2x.png");
const LIGHT_ICON_PATH: &[u8] = include_bytes!("../icons/light@2x.png");
// Determine icon based on theme
let icon_path: &[u8] = if is_dark_mode {
DARK_ICON_PATH
} else {
LIGHT_ICON_PATH
};
// Fetch tray by ID
if let Some(tray) = app.tray_by_id("tray") {
if let Err(e) = tray.set_icon(Some(
tauri::image::Image::from_bytes(icon_path)
.unwrap_or_else(|e| panic!("Failed to load icon from bytes: {}", e)),
)) {
eprintln!("Failed to set tray icon: {}", e);
}
} else {
eprintln!("Tray with ID 'tray' not found");
}
}
Frontend Invocation
import { invoke } from "@tauri-apps/api";
async function switchTrayIcon(value: "dark" | "light") {
try {
await invoke("switch_tray_icon", { isDarkMode: value === "dark" });
} catch (err) {
console.error("Failed to switch tray icon:", err);
}
}
Summary
- Tray Icon Features: Create customizable tray icons with menus and handle user interactions.
- Dynamic Theme Switching: Adjust tray icons dynamically to match light or dark themes.
- Frontend Integration: Seamlessly invoke backend commands to manage tray features.
This setup ensures a polished user experience with a functional and dynamic tray in your Tauri application.
Open Source Project Sharing
Recently, I started developing a project based on Tauri, called Coco. The project is open source, and we’re actively improving it. Feel free to check it out and give it a star 🌟 if you find it helpful!
This is my first project with Tauri, and I’ve been learning and exploring along the way. I look forward to connecting with like-minded developers to exchange ideas and grow together!
- Official Website: https://coco.rs/
- Frontend Repository: https://github.com/infinilabs/coco-app
- Backend Repository: https://github.com/infinilabs/coco-server
Thank you so much for your support and attention!
Top comments (1)
Where does the tray icon end up on Linux? Presumably it uses appindicator in some way?