Skip to main content
WebviewJS uses muda to render native menu bars on supported desktop platforms. Menus can be global (app-level, shared across windows) or per-window on Windows and Linux. macOS has one application-level menu bar. Custom menu items with an id emit custom-menu-click to your Node.js process.

Setting a global menu

Call app.setMenu(MenuOptions) to configure the global menu. Set it before creating windows on Windows and Linux, where the menu is attached during window construction. On macOS it configures the application-level menu and can be called at any time.
Calling setMenu() again replaces the current global menu definition. On Windows and Linux, the replacement is not reattached to existing windows; new windows use it. Configure the global menu before creating windows when all windows should receive the same menu. On macOS the application-level menu is updated. Pass null to remove the non-macOS global menu; macOS restores its default application menu.

Handling menu clicks

Listen for the custom-menu-click application event to respond to clicks on any menu item that has an id. The payload contains a customMenuEvent object with the clicked item’s identifier. Its windowId field is currently emitted as 0 and is not a reliable originating-window identifier.
Items that use a role (e.g. copy, quit) are handled natively and do not emit custom-menu-click.

Updating menus at runtime

Replace the global menu by calling app.setMenu() again with a new MenuOptions object. On Windows and Linux, the replacement is not reattached to existing windows; later-created windows use it. On macOS the application-level menu updates immediately.
To remove the menu bar entirely, pass null:

Per-window menus

On Windows and Linux, pass menu: MenuOptions when creating a window to attach a menu that overrides the global menu for that specific window. There is no win.setMenu() method. Windows without a per-window menu use the global menu attached when they were created; changing the global menu later does not reattach it. On macOS, the menu bar is application-level; use app.setMenu().
On Windows and Linux, if you use only a per-window menu, initialize menu event delivery before pumping the application by setting a non-null global menu with app.setMenu(...) or creating a tray icon. The current application loop starts draining menu events when one of those resources initializes its menu-event receiver.
Per-window menu clicks also fire custom-menu-click on app. The current customMenuEvent.windowId value is 0, so route clicks using your own window state when you need per-window behavior.
Every entry in a submenu.items array is a MenuItemOptions object.

Predefined roles

Roles map menu items to native platform actions and are automatically localised into the system language. You do not need to supply label, id, or accelerator for role items.
Availability follows Muda’s native backend. On Linux, the GTK backend supports separators, copy/cut/paste/select-all, and About items. The About item can be rendered, but WebviewJS does not provide About metadata and the default action is backend-dependent. The GTK backend omits the other predefined roles such as undo, minimize, fullscreen, close, and quit. Menus are disabled on Android, and the published FreeBSD target is a GUI stub.

Keyboard accelerators

An accelerator string defines a keyboard shortcut displayed next to the menu label. The format is a +-separated list of modifiers followed by a key name. Examples

Nested submenus

Set the submenu field on any menu item to create a hierarchical menu structure. The source supports recursive nested submenus; the native platform may impose its own rendering limits.
When an item has a submenu, the id and accelerator fields on that parent item are ignored — only label and enabled apply.

Platform differences

The menu system is disabled on Android. The published FreeBSD target is a GUI stub.