I've been trying to move a frameless window on false but now I want to move the whole window just by dragging one element (the title bar), I've tried -webkit-app-region: drag;
but it doesn't seem to work, I've also tried https://www.npmjs.com/package/electron-drag but it does't work either.
-
Please read the help section on how to ask a question – StudioTime Jun 29 '17 at 07:09
-
5What? the question is clear, what was so hard about "I cant move a frameless window on Electron" wtf – speed437 Jun 29 '17 at 07:11
-
1This tutorial shows how to create a draggable titlebar and it uses the -webkit-app-region: drag; css attribute, you may be doing something wrong: http://ourcodeworld.com/articles/read/287/how-to-create-a-custom-frameless-window-without-title-bar-with-minimize-maximize-and-close-controls-in-electron-framework – Carlos Delgado Jun 29 '17 at 07:11
-
It even says that -webkit-app-region doesnt even exist http://prntscr.com/fpguhc – speed437 Jun 29 '17 at 07:16
-
1The point is if you show what you've tried, instead of one random line, then we may see something else which might help you – StudioTime Jun 29 '17 at 07:20
-
Well now because of you I am not able to ask any more questions so I guess I'll just ask here. Why does my Webstorm editor (and browser) say http://prntscr.com/fpgx7r . (All settings are default) – speed437 Jun 29 '17 at 07:27
-
1Only because webstorm does not know this property it still can be valid. – Hans Koch Jun 29 '17 at 11:21
5 Answers
Since your windows are frameless you can use the property -webkit-app-region
which is valid even though your IDE says it's not. You just should forbid the text selection and drag on buttons inside of your title bar too out of UX concerns.
.titlebar {
-webkit-user-select: none;
-webkit-app-region: drag;
}
.titlebar-button {
-webkit-app-region: no-drag;
}
The API documentation mentions this too https://github.com/electron/electron/blob/master/docs/api/frameless-window.md#draggable-region

- 4,283
- 22
- 33
First create your app window with the frame
option set to false
on your main.js file:
mainWindow = new BrowserWindow({
...
frame: false
})
Then in your renderer.js file create an HTML element (Ex. ) with the -webkit-app-region
propperty set to drag
.
var windowTopBar = document.createElement('div')
windowTopBar.style.width = "100%"
windowTopBar.style.height = "32px"
windowTopBar.style.backgroundColor = "#000"
windowTopBar.style.position = "absolute"
windowTopBar.style.top = windowTopBar.style.left = 0
windowTopBar.style.webkitAppRegion = "drag"
document.body.appendChild(windowTopBar)

- 389
- 4
- 10
-
from vuejs app, insert that into index.html file into script tag html in begin of body. It works perfectly. – miltone Nov 17 '20 at 23:08
-
Will it always shows the close + minimize + fullscreen buttons ? It works on osx, but will it also preserve these buttons on window? – DoneDeal0 Jan 26 '23 at 21:11
I had the same problem. I realized that you must have property focusable
of BrowserWindow
to false
.
Example:
let auxWindow = new BrowserWindow({
frame: false,
transparent: false,
alwaysOnTop: true,
focusable: false, //THIS IS THE KEY
closable: true,
fullscreenable: false,
maximizable: false,
resizable: false,
webPreferences: {
preload: join(app.getAppPath(), 'build', 'src', 'preload.js'),
},
parent: mainWindow
});
Then, in your aux window, you only need to put a button with class="draggable"
:
<img src="move-outline.svg" width="15" height="15" alt="move" class="draggable">
And set in your CSS -webkit-app-region: drag;
:
.draggable {
-webkit-app-region: drag;
}

- 188
- 5
I had the same problem and after opening the Developer Tools Window (Ctrl+Shift+I) I noticed that inline code was being blocked by a Content Security Policy.
The solution was to move css into an external file
index.html
<link rel="stylesheet" type="text/css" href="style.css"/>
style.css
.draggable {
-webkit-user-select: none;
user-select: none;
-webkit-app-region: drag;
}
now anything with the draggable class is draggable and prevents the text from being selected

- 443
- 6
- 16
I was looking for something similar for my project, even though you should be good with webkit region for your use but It's not the answer you demanded, and If someone facing the issue below they can also use the code.
Im using frameless window, making the whole window element as draggable makes the program to ignore click events.
Worry Not, Im here to you a lot of "mehnat".
Rendering/front end side:
//elem = the element you want to use to drag the whole window.
//In my case, elem was the element covering the whole window. (100vh + 100 vw)
//longmousedown variable tells us if mouse been clicked for a long time, 200ms in my case.
//When longmousedown is true, I use this to ignore click event functions using if/else. (It feels better if click functions doesn't do anything while you trying to drag your window)
let longmousedowntimout;
let longmousedown = false;
let is_mousedownvid = false;
let earlymouseX,earlymouseY;
elem.addEventListener("mousedown", function(event){
longmousedowntimout = setTimeout(function(){longmousedown = true},200)
is_mousedownvid = true;
earlymouseX = event.screenX;
earlymouseY = event.screenY;
});
elem.addEventListener("mouseup", function(event){
clearTimeout(longmousedowntimout)
is_mousedownvid = false;
ipcRenderer.invoke('settlenewpos', {x:(event.screenX - earlymouseX),y:(event.screenY - earlymouseY)})
});
elem.addEventListener("mousemove", dragMouse);
elem.addEventListener("mouseleave", ()=>{
if(is_mousedownvid){
is_mousedownvid = false;
ipcRenderer.send("settlemergency")
}
});
function dragMouse(e){
if(is_mousedownvid){
e = e || window.event;
e.preventDefault();
ipcRenderer.invoke('setnewpos', {x:(e.screenX - earlymouseX),y:(e.screenY - earlymouseY)})
}}
Main.js side (the side where electron runs) :
(don't copy paste the below, read it once)
let earlyX, earlyY;
let newX, newY;
const createWindow = () => {
let display = screen.getPrimaryDisplay();
let widtho = display.bounds.width;
let heighto = display.bounds.height;
let wind_height = 330;
let wind_width = 0;
let minusX = 608;
let minusY = 376;
const mainWindow = new BrowserWindow({
icon: `${__dirname}/resources/icons/yt logo hd 2.png`,
show: false,
height: wind_height,
frame:false,
minimizable: true,
skipTaskbar:true,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration:true,
contextIsolation: false,
},
});
earlyX = widtho - minusX;
earlyY = heighto - minusY;
mainWindow.setBounds({
width: mainWindow.getSize()[0],
height: mainWindow.getSize()[1],
x: earlyX,
y: earlyY
});
mainWindow.setAspectRatio(16/9);
ipcMain.handle('setnewpos', async (event, someArgument) => {
mainWindow.setBounds({
width: wind_width || mainWindow.getSize()[0],
height: wind_height,
x: earlyX+someArgument.x,
y: earlyY+someArgument.y
});
newX = earlyX+someArgument.x;
newY = earlyY+someArgument.y;
if(wind_width == 0) wind_width = Math.ceil(parseInt(wind_height)*16/9)
})
ipcMain.handle('settlenewpos', async (event, someArgument) => {
earlyX=earlyX+someArgument.x;
earlyY=earlyY+someArgument.y;
newX = earlyX;
newY = earlyY;
})
ipcMain.on('settlemergency', () => {
earlyX = newX;
earlyY= newY;
})
mainWindow.on("will-resize",(event, newBounds)=>{
earlyX = newBounds.x;
earlyY = newBounds.y;
newX = earlyX;
newY = earlyY;
wind_height= newBounds.height
wind_width = newBounds.width
})
}

- 11
- 3