Skip to main content
WebviewJS exposes a cross-platform native menu system powered by muda. You define a tree of menu items — labels, roles, accelerators, and submenus — and the OS renders it natively. On macOS the menu bar lives at the top of the screen and belongs to the application. On Windows each window has its own menu bar embedded in the title bar. On Linux a per-window GTK menu bar is attached through Tao’s GTK integration; custom-menu-click events fire on all three platforms. See Platform differences for details.

Setting a global menu

Call app.setMenu(options) before creating windows when targeting Windows or Linux. Those platforms attach the global menu during window construction, so a later change does not reattach the replacement to existing windows. On macOS, app.setMenu() updates the application-level menu. A per-window menu overrides the global menu on Windows and Linux.

Handling menu clicks

Listen for custom-menu-click on the Application instance. The event payload contains a customMenuEvent object with the id you assigned to the menu item. The current native implementation emits windowId: 0, so do not use that field to identify the originating window.
Only items with an id property emit this event. Role-based items such as copy and paste are handled natively by the OS and do not emit custom-menu-click.

Updating menus at runtime

Replace the global menu definition by calling app.setMenu() again with a new item list. On Windows and Linux, the new definition is used by windows created after the call; it is not reattached to existing windows. On macOS the application-level menu updates immediately. Pass null to remove the global menu on Windows/Linux; macOS restores its default application menu.

Per-window menus

On Windows and Linux, pass menu in the BrowserWindowOptions when creating a window to assign a menu that applies only to that window. This overrides the global menu for that window. Clicks still emit custom-menu-click on the application. macOS has one application-level menu bar, so use app.setMenu() there instead of relying on per-window menus.
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.

Keyboard accelerators

Specify accelerators with the accelerator property on any custom menu item. Use the following cross-platform modifier tokens:

Predefined roles

Use role instead of id + label to get OS-native behavior without writing click handlers. Role items are rendered and wired by the platform when that backend supports them.
Linux uses Muda’s GTK backend. It 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. Unsupported predefined roles such as undo, minimize, fullscreen, close, and quit are omitted from the GTK menu.

Nested submenus

Nest a submenu inside any top-level or secondary menu item to create hierarchical menus.

Platform differences

On Linux, WebviewJS uses Muda’s GTK integration to attach a per-window menu bar, and custom-menu-click events fire for custom items. Configure the global menu before creating the window, or pass a menu option when creating the window. The visual appearance is determined by the GTK theme of the desktop environment.