Skip to content
Tauri

System Tray

Tauri allows you to create and customize a system tray for your application. This can enhance the user experience by providing quick access to common actions.

Configuration

First of all, update your Cargo.toml to include the necessary feature for the system tray.

src-tauri/Cargo.toml
tauri = { version = "2.0.0", features = [ "tray-icon" ] }

Usage

The tray API is available in both JavaScript and Rust.

Create a Tray Icon

Use the TrayIcon.new static function to create a new tray icon:

import { TrayIcon } from '@tauri-apps/api/tray';
const options = {
// here you can add a tray menu, title, tooltip, event handler, etc
};
const tray = await TrayIcon.new(options);

See TrayIconOptions for more information on the customization options.

Change the Tray Icon

When creating the tray you can use the application icon as the tray icon:

import { TrayIcon } from '@tauri-apps/api/tray';
import { defaultWindowIcon } from '@tauri-apps/api/app';
const options = {
icon: await defaultWindowIcon(),
};
const tray = await TrayIcon.new(options);

Add a Menu

To attach a menu that is displayed when the tray is clicked, you can use the menu option.

import { TrayIcon } from '@tauri-apps/api/tray';
import { Menu } from '@tauri-apps/api/menu';
const menu = await Menu.new({
items: [
{
id: 'quit',
text: 'Quit',
},
],
});
const options = {
menu,
menuOnLeftClick: true,
};
const tray = await TrayIcon.new(options);

Listen to Menu Events

On JavaScript you can attach a menu click event listener directly to the menu item:

  • Using a shared menu click handler

    import { Menu } from '@tauri-apps/api/menu';
    function onTrayMenuClick(itemId) {
    // itemId === 'quit'
    }
    const menu = await Menu.new({
    items: [
    {
    id: 'quit',
    text: 'Quit',
    action: onTrayMenuClick,
    },
    ],
    });
  • Using a dedicated menu click handler

    import { Menu } from '@tauri-apps/api/menu';
    const menu = await Menu.new({
    items: [
    {
    id: 'quit',
    text: 'Quit',
    action: () => {
    console.log('quit pressed');
    },
    },
    ],
    });

Listen to Tray Events

The tray icon emits events for the following mouse events:

  • click: triggered when the cursor receives a single left, right or middle click, including information on whether the mouse press was released or not
  • Double click: triggered when the cursor receives a double left, right or middle click
  • Enter: triggered when the cursor enters the tray icon area
  • Move: triggered when the cursor moves around the tray icon area
  • Leave: triggered when the cursor leaves the tray icon area
import { TrayIcon } from '@tauri-apps/api/tray';
const options = {
action: (event) => {
switch (event.type) {
case 'Click':
console.log(
`mouse ${event.button} button pressed, state: ${event.buttonState}`
);
break;
case 'DoubleClick':
console.log(`mouse ${event.button} button pressed`);
break;
case 'Enter':
console.log(
`mouse hovered tray at ${event.rect.position.x}, ${event.rect.position.y}`
);
break;
case 'Move':
console.log(
`mouse moved on tray at ${event.rect.position.x}, ${event.rect.position.y}`
);
break;
case 'Leave':
console.log(
`mouse left tray at ${event.rect.position.x}, ${event.rect.position.y}`
);
break;
}
},
};
const tray = await TrayIcon.new(options);

See TrayIconEvent for more information on the event payload.

Basic Menu Items

You can create various types of menu items:

import { Menu } from '@tauri-apps/api/menu';
const menu = await Menu.new({
items: [
{
id: 'item1',
text: 'Simple Item',
},
{
id: 'item2',
text: 'Item with Icon',
icon: 'terminal',
},
{
id: 'item3',
text: 'Item with Hotkey',
hotkey: 'CmdOrCtrl+Shift+A',
},
],
});

Check Menu Items

Check menu items can be toggled on and off:

import { Menu } from '@tauri-apps/api/menu';
const menu = await Menu.new({
items: [
{
id: 'check1',
text: 'Check Item',
checked: true,
},
{
id: 'check2',
text: 'Another Check',
checked: false,
},
],
});

You can create nested submenus:

import { Menu } from '@tauri-apps/api/menu';
const submenu = await Menu.new({
items: [
{
id: 'sub1',
text: 'Submenu Item 1',
},
{
id: 'sub2',
text: 'Submenu Item 2',
},
],
});
const menu = await Menu.new({
items: [
{
id: 'main',
text: 'Main Menu',
submenu,
},
],
});

Separators

Add separators to organize your menu:

import { Menu } from '@tauri-apps/api/menu';
const menu = await Menu.new({
items: [
{
id: 'item1',
text: 'Item 1',
},
{
type: 'Separator',
},
{
id: 'item2',
text: 'Item 2',
},
],
});

Advanced Features

Dynamic Menu Updates

You can update the tray menu dynamically:

import { TrayIcon } from '@tauri-apps/api/tray';
import { Menu } from '@tauri-apps/api/menu';
const tray = await TrayIcon.new({});
// Create initial menu
const initialMenu = await Menu.new({
items: [
{
id: 'item1',
text: 'Initial Item',
},
],
});
await tray.setMenu(initialMenu);
// Update menu later
const updatedMenu = await Menu.new({
items: [
{
id: 'item2',
text: 'Updated Item',
},
],
});
await tray.setMenu(updatedMenu);

Updating Menu Item Text

You can also update individual menu item text dynamically:

import { TrayIcon } from '@tauri-apps/api/tray';
import { Menu } from '@tauri-apps/api/menu';
const tray = await TrayIcon.new({});
// Create menu with an item
const menu = await Menu.new({
items: [
{
id: 'status',
text: 'Status: Ready',
},
],
});
await tray.setMenu(menu);
// Update the menu item text
const updatedMenu = await Menu.new({
items: [
{
id: 'status',
text: 'Status: Processing...',
},
],
});
await tray.setMenu(updatedMenu);

Real-time Text Updates

For real-time updates, you can use background threads to update menu item text:

use tauri::tray::TrayIconBuilder;
use tauri::menu::{Menu, MenuItem};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
let tray = TrayIconBuilder::new().build(app)?;
// Create menu item with Arc for sharing
let status_item = MenuItem::with_id(app, "status", "Status: Ready", true, None::<&str>)?;
let status_item_arc = Arc::new(status_item);
let menu = Menu::with_items(app, &[&status_item_arc])?;
tray.set_menu(Some(menu))?;
// Clone Arc for background thread
let status_item_clone = status_item_arc.clone();
// Start background thread to update text
thread::spawn(move || {
let mut counter = 0;
loop {
counter += 1;
let new_text = format!("Status: Count {}", counter);
// Update menu item text
if let Err(e) = status_item_clone.set_text(&new_text) {
eprintln!("Failed to update menu text: {}", e);
}
thread::sleep(Duration::from_secs(1));
}
});

Tooltip

Add a tooltip to your tray icon:

import { TrayIcon } from '@tauri-apps/api/tray';
const tray = await TrayIcon.new({
tooltip: 'My Application',
});

You can enable/disable menu items:

import { Menu } from '@tauri-apps/api/menu';
const menu = await Menu.new({
items: [
{
id: 'enabled',
text: 'Enabled Item',
enabled: true,
},
{
id: 'disabled',
text: 'Disabled Item',
enabled: false,
},
],
});

© 2025 Tauri Contributors. CC-BY / MIT