tauri-syntax-menu

Use when creating application menus, system tray icons, context menus, or handling menu events in Tauri 2. Prevents using deprecated v1 menu patterns and missing menu event handler registration on the

SKILL.md

GitHub

tauri-syntax-menu

Quick Reference

Menu Item Types (Rust)

Type Builder Purpose
MenuItem MenuItemBuilder Basic clickable text item
CheckMenuItem CheckMenuItemBuilder Toggleable checkbox item
IconMenuItem IconMenuItemBuilder Item with icon
PredefinedMenuItem -- OS-native standard items
Submenu SubmenuBuilder Nested menu container

PredefinedMenuItem Types (both Rust and JS)

Platform-standard items: About, Hide, HideOthers, ShowAll, CloseWindow, Quit, Copy, Cut, Paste, SelectAll, Undo, Redo, Minimize, Zoom, Separator, Fullscreen, Services, BringAllToFront.

SubmenuBuilder Convenience Methods (Rust)

Method Creates
.text(id, text) MenuItem with ID and text
.separator() Menu separator line
.quit() PredefinedMenuItem::Quit
.undo() PredefinedMenuItem::Undo
.redo() PredefinedMenuItem::Redo
.cut() PredefinedMenuItem::Cut
.copy() PredefinedMenuItem::Copy
.paste() PredefinedMenuItem::Paste
.select_all() PredefinedMenuItem::SelectAll

TrayIconBuilder Key Methods (Rust)

Method Signature Description
new() () -> Self Create builder
with_id(id) (impl Into<TrayIconId>) -> Self Set custom ID
icon(image) (Image) -> Self Set tray icon
tooltip(text) (impl Into<String>) -> Self Set tooltip
title(text) (impl Into<String>) -> Self Set title
menu(menu) (&Menu) -> Self Attach context menu
show_menu_on_left_click(bool) (bool) -> Self Show menu on left click (default: true)
icon_as_template(bool) (bool) -> Self macOS template icon
on_menu_event(F) (F) -> Self Menu click handler
on_tray_icon_event(F) (F) -> Self Tray icon click handler
build(manager) (impl Manager) -> Result<TrayIcon> Build tray icon

JS Menu Classes

Class Import Description
Menu @tauri-apps/api/menu Menu container
MenuItem @tauri-apps/api/menu Clickable text item
Submenu @tauri-apps/api/menu Nested menu
CheckMenuItem @tauri-apps/api/menu Toggleable item
PredefinedMenuItem @tauri-apps/api/menu OS-standard item
TrayIcon @tauri-apps/api/tray System tray icon

JS TrayIcon Event Types

Event Type Description
Click Tray icon clicked
DoubleClick Tray icon double-clicked
Enter Cursor entered tray icon
Move Cursor moved over tray icon
Leave Cursor left tray icon

JS TrayIcon Mouse Buttons

Left, Right, Middle

Critical Warnings

NEVER call Builder::on_menu_event() in Tauri 2 -- it was removed. Use App::on_menu_event() or the builder .on_menu_event() method instead.

NEVER use Tauri v1 menu type names (CustomMenuItem, SystemTray, MenuItem for predefined items) -- they are renamed in v2.

ALWAYS call .build() on MenuBuilder and SubmenuBuilder -- forgetting .build() produces a builder, not a usable menu.

ALWAYS match menu event IDs as strings using event.id().as_ref() in Rust -- menu item IDs are compared as string references, not typed enums.

ALWAYS use Menu.new() (not new Menu()) in JavaScript -- menu items are created via async factory methods.


Essential Patterns

Pattern 1: Application Menu (Rust)

use tauri::menu::{MenuBuilder, SubmenuBuilder, PredefinedMenuItem};

tauri::Builder::default()
    .menu(|app| {
        let file_menu = SubmenuBuilder::new(app, "File")
            .text("new", "New")
            .text("open", "Open")
            .separator()
            .quit()
            .build()?;

        let edit_menu = SubmenuBuilder::new(app, "Edit")
            .undo()
            .redo()
            .separator()
            .cut()
            .copy()
            .paste()
            .select_all()
            .build()?;

        MenuBuilder::new(app)
            .item(&file_menu)
            .item(&edit_menu)
            .build()
    })
    .on_menu_event(|app, event| {
        match event.id().as_ref() {
            "new" => println!("New file"),
            "open" => println!("Open file"),
            _ => {}
        }
    })
    .run(tauri::generate_context!())
    .expect("error running app");

Pattern 2: Application Menu (JavaScript)

import { Menu, MenuItem, Submenu, PredefinedMenuItem, CheckMenuItem } from '@tauri-apps/api/menu';

const menu = await Menu.new({
  items: [
    await Submenu.new({
      text: 'File',
      items: [
        await MenuItem.new({
          text: 'Open',
          accelerator: 'CmdOrCtrl+O',
          action: () => { console.log('Open clicked'); },
        }),
        await MenuItem.new({
          text: 'Save',
          accelerator: 'CmdOrCtrl+S',
          action: () => { console.log('Save clicked'); },
        }),
        await PredefinedMenuItem.new({ item: 'Separator' }),
        await PredefinedMenuItem.new({ item: 'Quit' }),
      ],
    }),
    await Submenu.new({
      text: 'View',
      items: [
        await CheckMenuItem.new({
          text: 'Dark Mode',
          checked: false,
          action: (item) => { console.log('Toggled'); },
        }),
      ],
    }),
  ],
});

await menu.setAsAppMenu();

Pattern 3: Context Menu (JavaScript)

// Show context menu at cursor position
await menu.popup();

// Show context menu at specific position
await menu.popup({ x: 100, y: 200 });

Pattern 4: System Tray (Rust)

use tauri::tray::TrayIconBuilder;
use tauri::menu::MenuBuilder;
use tauri::image::Image;

tauri::Builder::default()
    .setup(|app| {
        let menu = MenuBuilder::new(app)
            .text("show", "Show Window")
            .text("hide", "Hide Window")
            .separator()
            .text("quit", "Quit")
            .build()?;

        let _tray = TrayIconBuilder::new()
            .icon(Image::from_path("icons/tray.png")?)
            .tooltip("My Tauri App")
            .menu(&menu)
            .show_menu_on_left_click(true)
            .on_menu_event(|app, event| {
                match event.id().as_ref() {
                    "show" => {
                        if let Some(w) = app.get_webview_window("main") {
                            w.show().unwrap();
                        }
                    }
                    "quit" => app.exit(0),
                    _ => {}
                }
            })
            .on_tray_icon_event(|tray, event| {
                println!("Tray event: {:?}", event);
            })
            .build(app)?;

        Ok(())
    })
    .run(tauri::generate_context!())
    .expect("error running app");

Pattern 5: System Tray (JavaScript)

import { TrayIcon } from '@tauri-apps/api/tray';
import { Menu, MenuItem } from '@tauri-apps/api/menu';

const menu = await Menu.new({
  items: [
    await MenuItem.new({ text: 'Show', action: () => showWindow() }),
    await MenuItem.new({ text: 'Quit', action: () => exit(0) }),
  ],
});

const tray = await TrayIcon.new({
  icon: 'icons/tray-icon.png',
  tooltip: 'My App',
  menu,
  action: (event) => {
    if (event.type === 'Click') {
      console.log('Tray clicked with', event.button);
    }
  },
});

// Update at runtime
await tray.setTooltip('Updated tooltip');
await tray.setIcon('icons/new-icon.png');
await tray.setVisible(false);

Pattern 6: Menu Item Management (JavaScript)

// Dynamic menu manipulation
await menu.append(await MenuItem.new({ text: 'New Item', action: () => {} }));
await menu.prepend(await MenuItem.new({ text: 'First Item', action: () => {} }));
await menu.insert(1, await MenuItem.new({ text: 'At Index 1', action: () => {} }));
await menu.remove('item-id');
await menu.removeAt(0);

const item = await menu.get('item-id');
const allItems = await menu.items();

Menu Event Handling (Rust)

// On the builder
.on_menu_event(|app, event| {
    match event.id().as_ref() {
        "new" => println!("New file"),
        "open" => println!("Open file"),
        _ => {}
    }
})

The event.id() returns a MenuId. Use .as_ref() to get a &str for pattern matching.


Tray Configuration in tauri.conf.json

{
  "app": {
    "trayIcon": {
      "iconPath": "icons/icon.png",
      "iconAsTemplate": true
    }
  }
}

Permissions

Menu operations require core:menu:default and tray operations require core:tray:default in the capability file.

{
  "permissions": [
    "core:menu:default",
    "core:tray:default"
  ]
}

v1 to v2 Migration Names

Tauri v1 Tauri v2
Menu MenuBuilder
CustomMenuItem MenuItemBuilder
Submenu SubmenuBuilder
MenuItem (predefined) PredefinedMenuItem
SystemTray TrayIconBuilder
SystemTrayEvent TrayIconEvent

Reference Links

Official Sources