Build a Menu Bar Timer in Tauri 2 | System Tray Plugin Capstone

0views
C
CelesteAI
Description
A menu-bar app is a different animal from a regular desktop window. There is no dock icon and no big main window — just a small icon in the system tray that, when clicked, pops up a little panel. Hit the same icon again and the panel hides. Quit from a tray menu, not from a window close button. Tauri 2 has direct support for it via tauri::tray. Source code: https://github.com/GoCelesteAI/tauri_tomato This is the capstone of the Tauri Patterns for Production series. We build Tomato, a Pomodoro timer that lives in the menu bar. Click the tray icon, a 320 by 360 panel slides in with a 25:00 countdown and Start, Pause, Reset buttons. The session ticks down, an OS notification fires when it ends, and a daily-completions counter persists to disk. Every prior episode shows up somewhere: capabilities + bundle config (Ep 1), plugin-notification (Ep 3), WebviewWindow show/hide (Ep 4), plugin-store (Ep 5), Mutex AppState (Ep 7), and the CI matrix (Ep 9) still ships this app to three platforms without changes. What You'll Learn: - Menu-bar window config — visible: false, decorations: false, transparent: true, alwaysOnTop: true, skipTaskbar: true — five flags that turn a Tauri window into a tray popup. - TrayIconBuilder in the setup hook — registering the tray icon, attaching a right-click menu, handling left-click events. - show_menu_on_left_click(false) — left-click toggles your popup; right-click opens the menu. Standard menu-bar UX. - Mutex around TimerState — three coupled fields (running, started_at, remaining_secs) guarded by one Mutex, the same pattern from Episode 7. - Polling via setInterval calling invoke('tick') — simpler than events for a clock that updates twice a second. - app.notification().builder().title(...).body(...).show() — fire-and-forget OS notification when the session ends. - tauri-plugin-store for the daily counter — auto-save, JSON file on disk, survives quits and relaunches. - The capability permissions menu-bar apps need — core:window:allow-show, allow-hide, allow-set-focus, notification:default, store:default. Timestamps: 0:00 - The proof: tray click → popup → ticking → notification 0:32 - Cargo deps and tauri.conf.json window flags 1:30 - Capability permissions for the menu-bar pattern 2:00 - lib.rs — TimerState, four commands, the tray builder 4:20 - App.tsx — polling and the completed-today counter 5:30 - Live demo of the menu-bar flow 6:10 - Capstone recap Key Takeaways: 1. Window flags do most of the menu-bar work. Five flags in tauri.conf.json convert a normal Tauri window into a tray popup. The popup is the same WebviewWindow you'd use for any window — the OS treatment is what changes. This means everything you know about React, IPC, and state still applies; the OS just renders it differently. 2. show_menu_on_left_click(false) is the divergence point. Default tray behavior is "left-click opens menu." For a popup-on-click pattern, set this to false so your tray-icon event handler runs instead. Right-click still opens the menu, which is the right place for Quit and Settings. 3. The setup hook is the home for tray construction. Trays need access to the AppHandle, the default icon, and the right event loop. setup is where all three are alive. Building the tray on the Builder chain doesn't work because the handle isn't ready yet. 4. Polling is fine for low-frequency UI. A 500ms setInterval calling invoke('tick') is dead simple, has no backpressure, and updates twice a second — plenty for a countdown. Use Tauri events when the source is itself event-driven (file watcher, network status) or when you need many updates per second. 5. Plugins compose because capabilities make the boundary explicit. Adding tauri-plugin-notification means: one line in Cargo.toml, one .plugin(init()) call, one capability permission. The same pattern repeats for plugin-store, plugin-sql, plugin-updater. Once you have the rhythm, layering them in a real app is straightforward — which is the point of this whole capstone. This is the final episode of Tauri Patterns for Production — ten episodes, ten patterns, one production-shape app to tie them together. Source code and the full playlist linked in the description. This channel is run by Claude AI. Tutorials AI-produced; reviewed and published by Codegiz. Source code at codegiz.com. #Tauri #Tauri2 #Rust #DesktopApp #React #TypeScript #MenuBar #SystemTray #Pomodoro #ClaudeAI --- Generated by Claude AI · part of the Tauri Patterns for Production series
Back to tutorials

Duration

Added to Codegiz

May 17, 2026

📖 Read the articleOpen in YouTube