'How to access the mainWindow from another script in Electron?

My electron app defines the BrowserWindow mainWindow in the main.js. It loads an html and eventually inside of the html a script runs the function dialog.showMessageBox() which displays a simple warning:

dialog.showMessageBox({
    type: 'warning',
    message: "You have been warned.",
    buttons: ["OK"]
});

I want this dialog to be a child of the mainWindow b/c that makes it a modal, which disables the mainWindow until it is closed. To implement this you normally would just add mainWindow,before the type declaration. Unfortunately it doesn't know the variable mainWindow since the dialog.showMessageBox() is created in a different script (site.js).

How can I create a dialog, that is a child of the mainWindow without creating it in the main.js? Can ipc help somehow?



Solution 1:[1]

Current Electron versions (>= 14.0.0)

Starting with Electron 14.0.0, the below-mentioned remote module has been deprecated and subsequently removed. In order to still open these dialog boxes from the renderer process, I suggest to send a message to the main process via IPC:

// renderer process
const { ipcRenderer  } = require ("electron");

ipcRenderer.send ("show-message");

And the listening part in the main process:

// main process
const { dialog, ipcMain, BrowserWindow } = require ("electron");

ipcMain.on ("show-message", (event, args) => {
    dialog.showMessageBox (BrowserWindow.fromWebContents (event.sender), {
        type: "warning",
        message: "You have been warned.",
        buttons: ["OK"]
    });
});

This will open the message box as a modal dialog for the BrowserWindow instance which has sent the IPC message and will thus work as a drop-in replacement for the remote code.


Electron < 14.0.0

You can use Electron's remote module to get your current BrowserWindow from the script included (loaded) in that window:

const remote = require ("electron").remote;

dialog.showMessageBox (remote.getCurrentWindow (), {
  type: "warning",
  message: "You have been warned.",
  buttons: ["OK"]
});

Solution 2:[2]

The accepted answer is still correct, but quite old, and in the meantime the Electron team decided to slowly deprecate the remote module (more info here and here):

enter image description here


However, I was able to fix it by using BrowserWindow.getFocusedWindow(), which makes only one tiny assumption that the window which triggers the MsgBox is the one being currently focused (my guess is that in 99% of the cases that's true). Here's the updated code:

const { dialog, BrowserWindow } = require ("electron");

dialog.showMessageBox (BrowserWindow.getFocusedWindow(), {
  type: "warning",
  message: "You have been warned.",
  buttons: ["OK"]
});

Solution 3:[3]

To safely get the mainWindow in electron, I store its ID in a env variable and call BrowserWindow.fromId(ID) when needed.

BrowserWindow.getFocusedWindow() will not work in some case, for exemple if you load an URL from a child window to the main window.
I met some weird effect too, with BrowserWindow.getAllWindows() solution.

// store the ID at init time when you create your main window
process.env.MAIN_WINDOW_ID = mainWindow.id;
// every time you want the main window, call this function.
// don't forget to convert the env variable to type number otherwise this will throw an error.
const getMainWindow = () => {
  const ID = process.env.MAIN_WINDOW_ID * 1;
  return BrowserWindow.fromId(ID)
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Mihai Paraschivescu
Solution 3