Go Back Buy Me A Coffee 😇
Cover Image ElectronJs How to minimize/close window to system tray or in the background

ElectronJs How to minimize/close window to system tray or in the background

/ Closing apps in the system tray or taskbar is a common practice to manage computer resources and improve system performance. In this article let us look at how we can set it up on our electron projects.

#electron
#electronjs
✍️ BroJenuel
May. 28, 2023. 12:41 PM

First, you should have a basic knowledge of how electron works from creating a project to deploying it. Ok! let's get started.

First let's create a project by running this command, this will create a electron project for us automatically.

yarn create electron-app my-app

Then let us open my-app directory, and run this command to run our electron project:

yarn start

and this should open an electron dev app window, something like this.

OK! now that our app is working properly, let us now implement our tray, first let's use an electron tray. To learn more about tray you can go right here https://www.electronjs.org/docs/latest/api/tray.

First Let's add an icon, and let us name it to `icon.png`. Then let us create a tray icon. let us pass it on to our Tray class argument.

const { app, BrowserWindow, Tray, Menu } = require("electron");
//..other codes here
let tray = null;
//Set Tray
app.whenReady().then(() => {
    tray = new Tray(__dirname + "/icon.png");
    const contextMenu = Menu.buildFromTemplate([
        { label: "Item1", type: "normal" },
        { label: "Item2", type: "normal" },
        { label: "Item3", type: "normal" },
        { label: "Item4", type: "normal" },
    ]);
    tray.setToolTip("This is my application.");
    tray.setContextMenu(contextMenu);
});

//..other codes here

now restart the electron and you should see something like this. In my case, I am using this check icon image as my tray icon. If you right-click on it you should see the options we just created.

Now that Tray is working properly, let us set up our close function. Let us comment out this code, since we don't want our app to totally close.

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
    // if (process.platform !== "darwin") {
    //     app.quit();
    // }
});

Then in our createWindow function, lets add a event listener to listen for close event. This is for closing this specific window we just created.

const createWindow = () => {
    // Create the browser window.
    const mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, "preload.js"),
        },
    });

    // and load the index.html of the app.
    mainWindow.loadFile(path.join(__dirname, "index.html"));

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

    // add this code right here
    mainWindow.on("close", (event) => {
        mainWindow.close(); // so that we can close this window.
    });
};

Now when you restart the electron, even if you close the window, the icon in our tray is still running. This means our app did not quit and is running in the background.

The we can just create add a click event and quit option on the tray for us to reopen or totally quit the application. move this code just bellow the createWindow function. We create a function called handleQuit so that we can then add it to our quit option.

// to handle quitting
function handleQuit() {
    if (process.platform !== "darwin") {
        app.quit();
    }
}

app.whenReady().then(() => {
    tray = new Tray(__dirname + "/icon.png");
    const contextMenu = Menu.buildFromTemplate([
        { label: "Item1", type: "normal" },
        { label: "Item2", type: "normal" },
        { label: "Item3", type: "normal" },
        // let us then add handleQuit to click property
        { label: "Item4", type: "normal", click: handleQuit },
    ]);
    tray.setToolTip("This is my application.");
    tray.setContextMenu(contextMenu);

    // add this code
    // This will re-create the window if we click the icon in our tray.
    tray.addListener("click", () => createWindow());
});

Now, re-run your electron again, and it should only close when clicking the quit option in our tray.

This is the full code of our index.js re check how we implement it, and you can refactor it the way you want. I hope this article is helpful. cheers! 🥂🍻🍻🥂

const { app, BrowserWindow, Tray, Menu } = require("electron");
const path = require("path");

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require("electron-squirrel-startup")) {
    app.quit();
}

let tray = null;
// set Tray
const createWindow = () => {
    // Create the browser window.
    const mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            preload: path.join(__dirname, "preload.js"),
        },
    });

    // and load the index.html of the app.
    mainWindow.loadFile(path.join(__dirname, "index.html"));

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

    mainWindow.on("close", (event) => {
        mainWindow.close();
    });
};

function handleQuit() {
    if (process.platform !== "darwin") {
        app.quit();
    }
}

app.whenReady().then(() => {
    tray = new Tray(__dirname + "/icon.png");
    const contextMenu = Menu.buildFromTemplate([
        { label: "Item1", type: "normal" },
        { label: "Item2", type: "normal" },
        { label: "Item3", type: "normal" },
        { label: "Quit", type: "normal", click: handleQuit },
    ]);
    tray.setToolTip("This is my application.");
    tray.setContextMenu(contextMenu);
    tray.addListener("click", () => createWindow());
});

// 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.on("ready", createWindow);

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
    // if (process.platform !== "darwin") {
    //     app.quit();
    // }
});

app.on("activate", () => {
    // On OS X 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();
    }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and import them here.

If you enjoy this article and would like to show your support, you can easily do so by buying me a coffee. Your contribution is greatly appreciated!

Buy Me a Coffee at https://www.buymeacoffee.com