Search code examples
node.jswebviewelectroncontextmenuright-click

How to create a context menu in a webview in electron


I am working on a small electron app, and I seem to have hit a road block. I have a webview in my app that loads to www.google.com . The webview loads fine, but when I right click anywhere in the webview, no context menu is created, clicking on any part of the page that is not the webview results in a context menu being successfully created. I am using electron-content-menu to create the menus, and I read through the documentation included at the git repository: https://github.com/sindresorhus/electron-context-menu#readme, but got nothing of value. Any help would be appreciated, as I really need context menu's to appear in my webviews.

Main.js

// Modules to control application life and create native browser window
const {app, BrowserWindow, Menu, shell} = require('electron')
const path = require('path')
var holder;
var checkmax = 0;

function createWindow () {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 1919,
    height: 1079,
    frame: true,
    webPreferences: {
      webviewTag: true,
      preload: path.join(__dirname, 'preload.js'),
      nodeIntegration: true
      
    }
  })

  // and load the index.html of the app.
  mainWindow.loadFile('index.html');
  holder = mainWindow;


  // Open the DevTools.
  // mainWindow.webContents.openDevTools()
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
  createWindow()
  
  app.on('activate', function () {
    // On macOS it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

//testing context
const contextMenu = require('electron-context-menu');

contextMenu({
    prepend: (defaultActions, params, browserWindow) => [
        {
            label: 'Rainbow',
            // Only show it when right-clicking images
            visible: params.mediaType === 'image'
        },
        {
            label: 'Search Google for “{selection}”',
            // Only show it when right-clicking text
            visible: params.selectionText.trim().length > 0,
            click: () => {
                shell.openExternal(`https://google.com/search?q=${encodeURIComponent(params.selectionText)}`);
            }
        }
    ]
});

Index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body style="background-color:red;">
    <webview style="position: absolute; top: 10vh; left:0; width:100vw; height: 90vh;" src="https://www.google.com/"></webview>
  </body>
</html>

Solution

  • I figured it out after a ton of trial and error, and I came up with this, which works for any generated webviews within the page after the initialization.

    This goes in Main.js

    var menu = new Menu();
    
    //Basic Menu For Testing
    menu.append(new MenuItem({ label: 'MenuItem1', click: function() { console.log("YES"); 
    } }));
    menu.append(new MenuItem({ type: 'separator' }));
    menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true }));
    app.on("web-contents-created", (...[/* event */, webContents]) => {
    
    //Webview is being shown here as a window type
    console.log(webContents.getType())
    webContents.on("context-menu", (event, click) => {
      event.preventDefault();
      console.log(webContents.getType())
      menu.popup(webContents);
    }, false);
    });