1

Added a custom title bar to a frameless window in order to make the window draggable. The title bar shows, but eventListener won't fire:

main.js:

const createWindow = () => {
    const win = new BrowserWindow({
      width: 800,
      height: 600,
      frame: false,
      scrollbar: false,
      webPreferences:{
        nodeIntegration: true,
        contextIsolation: false,
      }
    })
    win.loadFile('index.html')
  }

index.html:

<body>
  <div class="window">
    <div class="window-content">
      <textarea>some content</textarea>
    </div>
  </div>
  <script src="index.js"></script>
</body>

index.js:

let titleBar = document.createElement('div')
titleBar.style.width = "100%"
titleBar.style.height = "32px"
titleBar.style.backgroundColor = "#fff"
titleBar.style.position = "absolute"
titleBar.style.top = titleBar.style.left = 0
titleBar.style.webkitAppRegion = "drag"
titleBar.textContent = 'My App';

document.body.appendChild(titleBar)

// Nothing happens
titleBar.addEventListener("mouseover", () => {
    console.log("hello")
})

2 Answers 2

0

Yes, it is possible to add an eventListener to a custom title bar used for window dragging in a frameless window, but it requires implementation of own mouse event code for dragging the window.

The issue with mouse events not triggering the eventListener is caused by

titleBar.style.webkitAppRegion = "drag"

which interferes with the mechanism of propagating the events and prevents the mouse events to be detected by the listener.

In other words it seems that in Electron you can't have both at the same time for same DOM-object: dragging using .style.webkitAppRegion = "drag" and receiving of the mouse events using .addEventListener("mouseover",. If you want the dragging behavior you need to implement it yourself using the from the DOM-object received mouse events.

To see it yourself comment or remove the "drag" line and experience that the mouse event is then working as expected ( don't forget that the console output is provided after Ctrl+Shift+i in the window of the application and not in the Terminal window running the application ).

Please be aware that using some "programming tricks" you can usually achieve any desired effect in any software system, so statements that something is not possible are generally not really correct from this perspective stating only that there is no straightforward simple and well known way of achieving something.

A possible workaround is to have two title bars (or a dragging icon next to the title bar in same line): one for dragging the window and the other one for responding to mouse events:

console.log("renderer.js loaded");

document.addEventListener('DOMContentLoaded', () => {
    // Create the draggable title bar at the very top
    let draggableTitleBar = document.createElement('div');
    draggableTitleBar.style.width = "100%";
    draggableTitleBar.style.height = "24px";
    draggableTitleBar.style.backgroundColor = "#e74c3c";
    draggableTitleBar.style.position = "absolute";
    draggableTitleBar.style.top = "0px";
    draggableTitleBar.style.left = "0px";
    draggableTitleBar.style.zIndex = "1000";
    draggableTitleBar.style.webkitAppRegion = "drag";
    draggableTitleBar.textContent = 'Draggable Title Bar';

    // Create the non-draggable title bar below it
    let nonDraggableTitleBar = document.createElement('div');
    nonDraggableTitleBar.style.width = "100%";
    nonDraggableTitleBar.style.height = "40px";
    nonDraggableTitleBar.style.backgroundColor = "#3498db";
    nonDraggableTitleBar.style.position = "absolute";
    nonDraggableTitleBar.style.top = "24px"; // Adjust position as needed
    nonDraggableTitleBar.style.left = "0px";
    nonDraggableTitleBar.style.zIndex = "1000";
    nonDraggableTitleBar.textContent = 'Non-Draggable Title Bar';

    // Add event listeners to the non-draggable title bar
    nonDraggableTitleBar.addEventListener("mouseover", () => {
        console.log("Mouseover event triggered on non-draggable title bar");
    });

    nonDraggableTitleBar.addEventListener("click", () => {
        console.log("Non-draggable title bar clicked");
    });

    // Append both title bars to the document body
    document.body.appendChild(draggableTitleBar);
    document.body.appendChild(nonDraggableTitleBar);

    console.log("Title bars added to the DOM");
});

Here how it looks like:

AppWindow with devTools Console

For the sake of completeness below code of an application which uses the title bar for both: dragging the window and reception of mouse events (logged to the console):


~ $ cat package.json 
{
    "name": "oOosysElectronApp",
    "version": "1.0.0",
    "main": "main.js",
    "scripts": {
        "start": "electron ."
    },
    "keywords": [],
    "author": "oOosys",
    "license": "---",
    "description": "PureGraphicWindowArea",
    "dependencies": {
        "electron": "^31.1.0"
    }
}
~ $ cat main.js
const { app, BrowserWindow, ipcMain } = require('electron');
// const path = require('path');

function createWindow() {
    const win = new BrowserWindow({
        width: 800,
        height: 480,
        frame: false,
        scrollbar: false,
        webPreferences: {
            nodeIntegration: true,
            contextIsolation: false,
        }
    });

    win.loadFile('index.html');

    ipcMain.on('get-window-position', (event) => {
        event.returnValue = win.getPosition();
    });

    ipcMain.on('set-window-position', (event, x, y) => {
    // console.log("set-window-position to x,y : ", x , y) // prints to TERMINAL 
        win.setPosition(x, y);
    });
}

app.whenReady().then(createWindow);

app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
        app.quit();
    }
});

app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
        createWindow();
    }
});
~ $ cat renderer.js
const { ipcRenderer } = require('electron');

console.log("renderer.js loaded");

document.addEventListener('DOMContentLoaded', () => {
    // Create the title bar
    let titleBar = document.createElement('div');
    titleBar.style.width = "100%";
    titleBar.style.height = "32px";
    titleBar.style.backgroundColor = "lightblue"; // Temporary background color for visibility
    titleBar.style.position = "absolute";
    titleBar.style.top = "0px";
    titleBar.style.left = "0px";
    titleBar.style.zIndex = "1000"; // Ensure the title bar is on top
    titleBar.textContent = 'Window Dragging Title';

    document.body.appendChild(titleBar);
    console.log("Title bar added to the DOM");

    let isDragging = false;
    let startX, startY;
    let startWindowX, startWindowY;

    titleBar.addEventListener("mousedown", (event) => {
        event.preventDefault();
        event.stopPropagation();
        isDragging = true;
        startX = event.clientX;
        startY = event.clientY;
        const [windowX, windowY] = ipcRenderer.sendSync('get-window-position');
        startWindowX = windowX;
        startWindowY = windowY;
        console.log("MouseDOWN windowX,Y, mouseX,Y:", startWindowX, startWindowY, startX, startY);
    });

    // mousemove event interferes somehow with 
    //          ipcRenderer.send('set-window-position', newWindowX, newWindowY);
    //      causing the window to resize instead of re-position
    // In other words CONTINUOUS DRAGGING of the window FAILS TO WORK as expected
    
    document.addEventListener("mouseup", (event) => {
        if ( isDragging ) {
            const currentX = event.clientX;
            const currentY = event.clientY;
            const deltaX = currentX - startX;
            const deltaY = currentY - startY;
            const newWindowX = startWindowX + deltaX;
            const newWindowY = startWindowY + deltaY;
            ipcRenderer.send('set-window-position', newWindowX, newWindowY);
            console.log("mouseUP newWindowX,Y mouseMovedDistXY:", newWindowX, newWindowY, deltaX, deltaY);
            isDragging = false;
        }
    });
});
~ $ cat index.html
<!DOCTYPE html>
<html><head><title>oOosys Electron App</title>
<style>
    body, html {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
        overflow: hidden;
         background-color: #d0eed0;
    }
</style></head>
<body>
    <script src="renderer.js"></script>
    
    <br><br><br><br><br><br><br><br><br>
    <textarea>some content</textarea>
</body></html>
~ $ npm start 2>/dev/null

> [email protected] start
> electron .

And here how it looks like after the code documented in the log of a shell session provided above is executed:

movedWindow

Please notice that the window moves to the target position on mouseup event. The mousemove event seems to interfere with the functionality of ipcRenderer.send('set-window-position', newWindowX, newWindowY); resulting in resizing the window instead of moving so this approach seems not be able to provide smooth continuous dragging of the window due to an issue with Electron functionality.

3
  • Thanks for the workaround, would not be an option though for me. So in the end the answer is (quoting you): "in Electron you can't have both at the same time: the dragging and the firing of the mouse events."
    – nBar
    Commented Jul 2 at 9:29
  • @nBar : see my updated answer for an example of an application using the title bar for both purposes: receiving mouse events and dragging the window.
    – oOosys
    Commented Jul 2 at 17:28
  • That indeed is a workaround that's working well! The dragging is not exactly smooth, but it works. So with your solution it is in fact possible in Electron, to have a draggable custom title bar that can also receive mouse events.
    – nBar
    Commented Jul 3 at 19:42
0

You don't need to use eventListener, you can achieve this use only CSS.

main.js

const createWindow = () => {
const win = new BrowserWindow({
  width: 800,
  height: 600,
  frame: false,
  scrollbar: false,
  titleBarStyle: 'hidden',//Add this
  titleBarOverlay: {
   color: '#ecf2f9',
   symbolColor: '#003d99',
   height: 40,
  },//Add this for windows
  webPreferences:{
    nodeIntegration: true,
    contextIsolation: false,
  }
})
win.loadFile('index.html')
}

index.html

 <body>
<div class="titleBar">
My App
</div>
<div class="window">
  <div class="window-content">
    <textarea>some content</textarea>
  </div>
</div>
<script src="index.js"></script>

index.css

.titleBar{
background-color: #ecf2f9;
height: 40px; /* Adjust height as needed */
-webkit-app-region: drag; /*Allow dragging the window */
.
.
.
}
1
  • Many thanks for showing an alternative way of creating a custom title bar. This however also does not allow any eventListeners to be detected. So like @oOosys says, with a draggable title bar, eventListeners don't seem to be possible.
    – nBar
    Commented Jul 2 at 9:26

Not the answer you're looking for? Browse other questions tagged or ask your own question.