Context menus
A context menu is the menu that appears on a right click. Electron has none by default: right-clicking an input field shows nothing. The menu is created with the same Menu.buildFromTemplate as the app menu, but shown with the popup method in the right place.
A menu for input fields
The main process learns about a right click from the context-menu event of the window's webContents. Add to createWindow in main.js:
// main.js
win.webContents.on('context-menu', (event, params) => {
if (!params.isEditable) {
return;
}
const menu = Menu.buildFromTemplate([
{ role: 'cut' },
{ role: 'copy' },
{ role: 'paste' },
{ type: 'separator' },
{ role: 'selectAll' },
]);
menu.popup({ window: win });
});params.isEditable is true when the click landed on an input field. Right-click the note field — a menu with the familiar commands appears. Roles perform their actions themselves, so no click is needed.
What params holds
| Field | Value |
|---|---|
isEditable | The click was on an input field |
selectionText | The selected text |
linkURL | The link address under the cursor |
x, y | Click coordinates |
A menu for a note
To delete a specific note, the main process needs to know which one was clicked. Only the page knows that, so the page itself asks for the menu:
// renderer.js
list.addEventListener('contextmenu', (event) => {
const li = event.target.closest('li');
if (!li) {
return;
}
event.preventDefault();
window.notes.showNoteMenu(Number(li.dataset.index));
});When the list is rendered, each li gets li.dataset.index = i. preventDefault cancels the default handling of the right click.
// preload.js
showNoteMenu: (index) => ipcRenderer.send('notes:menu', index),
onDeleteNote: (callback) => ipcRenderer.on('notes:delete', (event, index) => callback(index)),Showing the menu in the main process
// main.js
ipcMain.on('notes:menu', (event, index) => {
const menu = Menu.buildFromTemplate([
{ label: 'Delete note', click: () => event.sender.send('notes:delete', index) },
]);
menu.popup({ window: BrowserWindow.fromWebContents(event.sender) });
});No answer is needed, so the send and ipcMain.on pair is used. The chosen item sends the note's index back to the page on the notes:delete channel.
// renderer.js
window.notes.onDeleteNote(async (index) => {
notes.splice(index, 1);
await window.notes.save(notes);
render();
});Right-clicking a note and choosing "Delete note" removes it from the list and the file.
Common mistake
Without the window option, popup opens the menu on the currently focused window, and with several windows it may appear in the wrong place. Always pass the window the click came from: menu.popup({ window: win }).