Ir al contenido

Window Menu

Esta página aún no está disponible en tu idioma.

Native application menus can be attached to both to a window or system tray. Available on desktop.

To create a base-level native window menu, and attach to a window. You can create various types of menu items including basic items, check items, and separators:

Use the Menu.new static function to create a window menu:

import { Menu } from '@tauri-apps/api/menu';
await using menu = await Menu.new({
items: [
{
id: 'quit',
text: 'Quit',
action: () => {
console.log('quit pressed');
},
},
{
id: 'check_item',
text: 'Check Item',
checked: true,
},
{
item: 'Separator',
},
{
id: 'disabled_item',
text: 'Disabled Item',
enabled: false,
},
{
id: 'status',
text: 'Status: Processing...',
},
],
});
// If a window was not created with an explicit menu or had one set explicitly,
// this menu will be assigned to it.
await menu.setAsAppMenu();
// Update individual menu item text
await using statusItem = await menu.get('status');
if (statusItem) {
await statusItem.setText('Status: Ready');
}

Each custom menu item triggers an event when clicked. Use the on_menu_event API to handle them.

import { Menu } from '@tauri-apps/api/menu';
await using menu = await Menu.new({
items: [
{
id: 'Open',
text: 'open',
action: () => {
console.log('open pressed');
},
},
{
id: 'Close',
text: 'close',
action: () => {
console.log('close pressed');
},
},
],
});
await menu.setAsAppMenu();

Multi-level menus allow you to group menu items under categories like “File,” “Edit,” etc. These will appear as part of the application window for Windows or Linux, or in the menu bar on MacOS.

Note: When using submenus on MacOS, all items must be grouped under a submenu. Top-level items will be ignored. Additionally, the first submenu will be placed under the application’s about menu by default, regardless of the text label. You should include a submenu as the first entry (say, an “About” submenu) to fill this space.

import { Menu, MenuItem, Submenu } from '@tauri-apps/api/menu';
// Will become the application submenu on MacOS
await using aboutSubmenu = await Submenu.new({
text: 'About',
items: [
{
id: 'quit',
text: 'Quit',
action: () => {
console.log('Quit pressed');
},
},
],
});
await using fileSubmenu = await Submenu.new({
text: 'File',
icon: 'folder', // Optional: Add an icon to the submenu
items: [
{
id: 'new',
text: 'New',
action: () => {
console.log('New clicked');
},
},
{
id: 'open',
text: 'Open',
action: () => {
console.log('Open clicked');
},
},
{
id: 'save_as',
text: 'Save As...',
action: () => {
console.log('Save As clicked');
},
},
],
});
await using editSubmenu = await Submenu.new({
text: 'Edit',
items: [
{
id: 'undo',
text: 'Undo',
action: () => {
console.log('Undo clicked');
},
},
{
id: 'redo',
text: 'Redo',
action: () => {
console.log('Redo clicked');
},
},
],
});
await using menu = await Menu.new({
items: [aboutSubmenu, fileSubmenu, editSubmenu],
});
await menu.setAsAppMenu();
// You can also update the submenu icon dynamically
await fileSubmenu.setIcon('document');
// Or set a native icon (only one type applies per platform)
await fileSubmenu.setNativeIcon('NSFolder');

To use built-in (native) menu items that has predefined behavior by the operating system or Tauri:

import { Menu, PredefinedMenuItem } from '@tauri-apps/api/menu';
await using copy = await PredefinedMenuItem.new({
text: 'copy-text',
item: 'Copy',
});
await using separator = await PredefinedMenuItem.new({
text: 'separator-text',
item: 'Separator',
});
await using undo = await PredefinedMenuItem.new({
text: 'undo-text',
item: 'Undo',
});
await using redo = await PredefinedMenuItem.new({
text: 'redo-text',
item: 'Redo',
});
await using cut = await PredefinedMenuItem.new({
text: 'cut-text',
item: 'Cut',
});
await using paste = await PredefinedMenuItem.new({
text: 'paste-text',
item: 'Paste',
});
await using select_all = await PredefinedMenuItem.new({
text: 'select_all-text',
item: 'SelectAll',
});
await using menu = await Menu.new({
items: [copy, separator, undo, redo, cut, paste, select_all],
});
await menu.setAsAppMenu();

If you want to change the status of the menu, such as text, icon, or check status, you can set_menu again:

import {
Menu,
CheckMenuItem,
IconMenuItem,
MenuItem,
} from '@tauri-apps/api/menu';
import { Image } from '@tauri-apps/api/image';
let currentLanguage = 'en';
await using check_sub_item_en = await CheckMenuItem.new({
id: 'en',
text: 'English',
checked: currentLanguage === 'en',
action: () => {
currentLanguage = 'en';
check_sub_item_en.setChecked(currentLanguage === 'en');
check_sub_item_zh.setChecked(currentLanguage === 'cn');
console.log('English pressed');
},
});
await using check_sub_item_zh = await CheckMenuItem.new({
id: 'zh',
text: 'Chinese',
checked: currentLanguage === 'zh',
action: () => {
currentLanguage = 'zh';
check_sub_item_en.setChecked(currentLanguage === 'en');
check_sub_item_zh.setChecked(currentLanguage === 'zh');
check_sub_item_zh.setAccelerator('Ctrl+L');
console.log('Chinese pressed');
},
});
// Load icon from path
await using icon = await Image.fromPath('../src/icon.png');
await using icon2 = await Image.fromPath('../src/icon-2.png');
await using icon_item = await IconMenuItem.new({
id: 'icon_item',
text: 'Icon Item',
icon: icon,
action: () => {
icon_item.setIcon(icon2);
console.log('icon pressed');
},
});
await using text_item = await MenuItem.new({
id: 'text_item',
text: 'Text Item',
action: () => {
text_item.setText('Text Item Changed');
console.log('text pressed');
},
});
await using menu = await Menu.new({
items: [
{
id: 'change menu',
text: 'change_menu',
items: [text_item, check_sub_item_en, check_sub_item_zh, icon_item],
},
],
});
await menu.setAsAppMenu();

There’re a few gotchas you should be aware of when using the JavaScript menu APIs, mainly because JavaScript does not have any way to run cleanup code when an object is being removed by garbage collection:

  • The menus will not clean up automatically unless close is called or closed by await using after the binding variable goes out of scope.
  • You should close the menu items you got e.g. from Menu.get, the await using syntax makes it easier, for example: await using status = menu.get('status') Be careful with APIs that can return a Menu such as Menu.setAsAppMenu, you’ll need to close them when you’re done with them or if you don’t plan to use them.
  • You should close the menu resource whenever you don’t need to access it in JavaScript anymore.

For example:

const copy = await PredefinedMenuItem.new({ item: 'Copy' });
const menu = await Menu.new({ items: [copy] });
// `copy` is now managed by the `menu` and the JavaScript resource reference can be closed
await copy.close();
const prev = await menu.setAsAppMenu();
// `menu` is now set as the app menu, we can close the JavaScript resource reference
await menu.close();
// We don't plan to use the previously set menu, close it here.
await prev?.close();

© 2026 Tauri Contributors. CC-BY / MIT