I'm making Chrome extension. I'm trying to make popup to be draggable and to be able to move it around screen. I'm able to move it but it's stuck to the right side of screen until it reaches max-width
. What am I doing wrong?
Here's simplified code.
const popup = document.getElementById("popup");
const dragBtn = document.getElementById("drag-btn");
let offsetX, offsetY, isDragging = false;
dragBtn.addEventListener("mousedown", (e) => {
isDragging = true;
offsetX = e.clientX - popup.offsetLeft;
offsetY = e.clientY - popup.offsetTop;
});
document.addEventListener("mousemove", (e) => {
if (isDragging) {
popup.style.left = `${e.clientX - offsetX}px`;
popup.style.top = `${e.clientY - offsetY}px`;
}
});
document.addEventListener("mouseup", (e) => {
isDragging = false;
});
#popup {
position: fixed;
top: 20px;
right: 20px;
min-width: 350px;
max-width: 500px;
background: var(--dark-bg, #222);
color: var(--dark-text, #fff);
border: 1px solid #333;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.4);
padding: 15px;
border-radius: 8px;
z-index: 10000;
}
#popup-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
#popup-title {
font-size: 14px;
font-weight: bold;
}
button {
border: none;
cursor: pointer;
border-radius: 4px;
font-size: 16px;
width: 26px;
height: 26px;
text-align: center;
padding: 0;
}
#drag-btn {
background: #326042;
color: white;
cursor: grab;
}
#theme-btn {
background: #ef713b;
color: white;
}
#close-btn {
background: #ff5252;
color: white;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Song Lyrics Finder</title>
<link rel="stylesheet" href="src/style.css">
</head>
<body>
<div id="popup">
<div id="popup-header">
<p id="popup-title">Song Lyrics Finder (from Genius.com)</p>
<div style="display: flex; align-items: center; gap: 5px;">
<button id="drag-btn">✥</button>
<button id="theme-btn">◑</button>
<button id="close-btn">⮿</button>
</div>
</div>
</div>
</body>
</html>
Because the element has a right
value, and you're changing the left
value, you are stretching the element until it reaches maximum size.
I would change the position using transform instead. In addition to not tempering with the width of the element, the performance is usually better (see in this SO answer):
const popup = document.getElementById("popup");
const dragBtn = document.getElementById("drag-btn");
let offsetX, offsetY, isDragging = false;
dragBtn.addEventListener("mousedown", (e) => {
isDragging = true;
// get previous translate values
const [tranX, tranY] = (popup.style.translate || '0 0').split(' ').map(v => parseInt(v, 10));
offsetX = e.clientX - tranX;
offsetY = e.clientY - tranY;
});
document.addEventListener("mousemove", (e) => {
if (!isDragging) return;
popup.style.translate = `${e.clientX - offsetX}px ${e.clientY - offsetY}px`;
});
document.addEventListener("mouseup", (e) => {
isDragging = false;
});
#popup {
position: fixed;
top: 20px;
right: 20px;
min-width: 350px;
max-width: 500px;
background: var(--dark-bg, #222);
color: var(--dark-text, #fff);
border: 1px solid #333;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.4);
padding: 15px;
border-radius: 8px;
z-index: 10000;
transform-style: preserve-3d;
}
#popup-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
#popup-title {
font-size: 14px;
font-weight: bold;
}
button {
border: none;
cursor: pointer;
border-radius: 4px;
font-size: 16px;
width: 26px;
height: 26px;
text-align: center;
padding: 0;
}
#drag-btn {
background: #326042;
color: white;
cursor: grab;
}
#theme-btn {
background: #ef713b;
color: white;
}
#close-btn {
background: #ff5252;
color: white;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Song Lyrics Finder</title>
<link rel="stylesheet" href="src/style.css">
</head>
<body>
<div id="popup">
<div id="popup-header">
<p id="popup-title">Song Lyrics Finder (from Genius.com)</p>
<div style="display: flex; align-items: center; gap: 5px;">
<button id="drag-btn">✥</button>
<button id="theme-btn">◑</button>
<button id="close-btn">⮿</button>
</div>
</div>
</div>
</body>
</html>
Another option is to reset right
to auto
and set the current left
on mouse down event, because we're going to update the left
from now on:
const popup = document.getElementById("popup");
const dragBtn = document.getElementById("drag-btn");
let offsetX, offsetY, isDragging = false;
dragBtn.addEventListener("mousedown", (e) => {
isDragging = true;
const { left } = popup.getBoundingClientRect();
// set right to auto so it won't interfere
popup.style.right = 'auto';
// set left
popup.style.left = `${left}px`;
offsetX = e.clientX - popup.offsetLeft;
offsetY = e.clientY - popup.offsetTop;
});
document.addEventListener("mousemove", (e) => {
if (!isDragging) return;
popup.style.left = `${e.clientX - offsetX}px`;
popup.style.top = `${e.clientY - offsetY}px`;
});
document.addEventListener("mouseup", (e) => {
isDragging = false;
});
#popup {
position: fixed;
top: 20px;
right: 20px;
min-width: 350px;
max-width: 500px;
background: var(--dark-bg, #222);
color: var(--dark-text, #fff);
border: 1px solid #333;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.4);
padding: 15px;
border-radius: 8px;
z-index: 10000;
}
#popup-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
#popup-title {
font-size: 14px;
font-weight: bold;
}
button {
border: none;
cursor: pointer;
border-radius: 4px;
font-size: 16px;
width: 26px;
height: 26px;
text-align: center;
padding: 0;
}
#drag-btn {
background: #326042;
color: white;
cursor: grab;
}
#theme-btn {
background: #ef713b;
color: white;
}
#close-btn {
background: #ff5252;
color: white;
}
<div id="popup">
<div id="popup-header">
<p id="popup-title">Song Lyrics Finder (from Genius.com)</p>
<div style="display: flex; align-items: center; gap: 5px;">
<button id="drag-btn">✥</button>
<button id="theme-btn">◑</button>
<button id="close-btn">⮿</button>
</div>
</div>
</div>