The application menu
The application menu is the File, Edit, View bar at the top of the window on Windows and Linux, or at the top of the screen on macOS. Electron installs a default menu, and your own is described as a template array in the main process. The menu is a good place for commands that are always needed: New note, Export, Quit.
The menu template
Each array element is a top-level item, and submenu holds its nested items. Add to main.js:
// main.js
const { app, BrowserWindow, Menu } = require('electron');
function createMenu() {
const template = [
{
label: 'File',
submenu: [
{ label: 'New note', accelerator: 'CmdOrCtrl+N', click: () => console.log('New note') },
{ type: 'separator' },
{ role: 'quit' },
],
},
];
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
}
app.whenReady().then(() => {
createMenu();
createWindow();
});buildFromTemplate turns the array into a menu, and setApplicationMenu makes it the app menu. Press Ctrl+N (Cmd+N on a Mac) — "New note" appears in the terminal.
Item properties
| Property | What it sets |
|---|---|
label | Item text |
click | Function called when chosen |
accelerator | Key combination, e.g. 'CmdOrCtrl+S' |
role | A built-in Electron action |
type | 'separator', 'checkbox', 'radio' |
submenu | Nested items |
enabled, visible | Whether the item is enabled and visible |
CmdOrCtrl means Cmd on macOS and Ctrl on Windows and Linux.
Roles
A role is a standard action Electron performs itself: copy, paste, reload the window. Whole sections have roles too:
// main.js
const template = [
{ label: 'File', submenu: [{ role: 'quit' }] },
{ role: 'editMenu' },
{ role: 'viewMenu' },
{ role: 'windowMenu' },
];editMenu adds Undo, Cut, Copy and Paste; viewMenu adds reload, DevTools and zoom.
A command for the page
A new note is created on the page, so the menu item sends it a message:
// main.js
{
label: 'New note',
accelerator: 'CmdOrCtrl+N',
click: (menuItem, win) => win?.webContents.send('menu:new-note'),
},The second argument of click is the window that was focused. With no windows it is undefined, hence the ?..
// preload.js
onNewNote: (callback) => ipcRenderer.on('menu:new-note', () => callback()),// renderer.js
window.notes.onNewNote(() => {
text.value = '';
text.focus();
});Now Ctrl+N clears the field and puts the cursor in it.
The menu on macOS
On macOS the first menu is always named after the app. It has the appMenu role:
// main.js
const isMac = process.platform === 'darwin';
const template = [
...(isMac ? [{ role: 'appMenu' }] : []),
{ label: 'File', submenu: [{ role: isMac ? 'close' : 'quit' }] },
];Common mistake
If you replace the menu with your own and leave out a section with the editMenu role, Cmd+C and Cmd+V stop working in text fields on macOS: there these keys work only through menu items. Always keep an Edit section with roles in the template.