Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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

PropertyWhat it sets
labelItem text
clickFunction called when chosen
acceleratorKey combination, e.g. 'CmdOrCtrl+S'
roleA built-in Electron action
type'separator', 'checkbox', 'radio'
submenuNested items
enabled, visibleWhether 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.

Thanks for reading!

Donate to the site — we work hard for you.