import { Application } from '@webviewjs/webview';
const app = new Application();
app.setMenu({
items: [
{
label: 'File',
submenu: {
items: [
{ id: 'new', label: 'New', accelerator: 'CmdOrCtrl+N' },
{ id: 'open', label: 'Open', accelerator: 'CmdOrCtrl+O' },
{ role: 'separator' },
{ role: 'quit' },
],
},
},
{
label: 'Edit',
submenu: {
items: [
{ role: 'undo' },
{ role: 'redo' },
{ role: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
],
},
},
],
});
app.on('custom-menu-click', ({ customMenuEvent }) => {
switch (customMenuEvent.id) {
case 'new':
createNewWindow();
break;
case 'open':
openFilePicker();
break;
}
});
// Replace the whole menu
app.setMenu({ items: updatedItems });
// Remove entirely
app.setMenu(null);
Windows, child popups, and dialogs can have their own distinct menus:
const win = app.createBrowserWindow({ title: 'Editor' });
win.setMenu({
items: [{ label: 'Editor', submenu: { items: [{ id: 'editor-prefs', label: 'Preferences' }] } }],
});
Per-window menus override the global menu for that window. Clicking items emits
custom-menu-click on the application.
{
label: 'View',
submenu: {
items: [
{
label: 'Zoom',
submenu: {
items: [
{ id: 'zoom-in', label: 'Zoom In', accelerator: 'CmdOrCtrl+=' },
{ id: 'zoom-out', label: 'Zoom Out', accelerator: 'CmdOrCtrl+-' },
{ id: 'zoom-reset', label: 'Reset', accelerator: 'CmdOrCtrl+0' },
],
},
},
{ role: 'fullscreen' },
],
},
}
CmdOrCtrl+S → Cmd+S on macOS, Ctrl+S elsewhere
Alt+F4 → literal Alt+F4
Shift+CmdOrCtrl+Z → redo shortcut
F5, F11 → function keys
| Feature | Windows | macOS | Linux |
|---|---|---|---|
| Menu bar | Per-window, inside title bar | App-level, top of screen | Not supported |
| Predefined roles | Most | All | N/A |
| Accelerators | Yes | Yes | N/A |
CustomMenuClick events |
Yes | Yes | Never fires |