Hello devs.
Quick heads up : This post is a tutorial for beginners and anyone who hasn't implemented something like this before.
The Objective
Create a div that can be dragged and re-positioned anywhere else on the screen.
Let's code!
In Vanilla JavaScript
First, we will need to create a test UI.
<!DOCTYPE html>
<html lang="en">
<body>
<div id="target" style="background-color: red;width: 400px;height: 400px;" ></div>
</body>
</html>
Our HTML only contains one div for simplicity
Let's add some basic styles
<style>
#target {
position: absolute;
background-color: red;
width: 400px;
height: 400px;
}
</style>
Note the position: absolute
value is necessary for the code to work.
Next, we write the script that enables the drag and drop feature.
<script>
// first we select the div
const target = document.getElementById("target");
// for simplicity and performance, mouse events are used instead of drag and drop events
// we define our mousedown function
const mousedown = (e) => {
// get the initial position of the cursor
let offsetX = e.clientX;
let offsetY = e.clientY;
const mousemove = (e) => {
// calculate the new position
let newX = offsetX - e.clientX;
let newY = offsetY - e.clientY;
const rect = target.getBoundingClientRect();
// update the position of the target div
target.style.top = rect.top - newY + "px";
target.style.left = rect.left - newX + "px";
// reset the offset* properties to the cursor position
offsetX = e.clientX;
offsetY = e.clientY;
};
// clean up the event listeners
const mouseup = () => {
window.removeEventListener("mousemove", mousemove);
window.removeEventListener("mouseup", mouseup);
};
// the listeners are added to our window, to account for the cursor leaving the target div while the mousedown event is still firing
window.addEventListener("mousemove", mousemove);
window.addEventListener("mouseup", mouseup);
}
// add the mousedown listener to the target element
target.addEventListener("mousedown", mousedown);
</script>
In React
I extracted this logic into a custom React Hook, to make it reusable.
export const useDragNPosition = (ref) => {
const mousedown = (e) => {
let offsetX = e.clientX;
let offsetY = e.clientY;
const mousemove = (e) => {
let newX = offsetX - e.clientX;
let newY = offsetY - e.clientY;
const rect = ref.current.getBoundingClientRect();
ref.current.style.top = rect.top - newY + "px";
ref.current.style.left = rect.left - newX + "px";
offsetX = e.clientX;
offsetY = e.clientY;
};
const mouseup = () => {
window.removeEventListener("mousemove", mousemove);
window.removeEventListener("mouseup", mouseup);
};
window.addEventListener("mousemove", mousemove);
window.addEventListener("mouseup", mouseup);
};
return mousedown;
};
The React component utilizes the useRef hook, to access the target element.
import { useRef } from "react";
import { useDragNPosition } from "useDragNPosition";
const target = () => {
const targetRef = useRef(null);
const mousedown = useDragNPosition(targetRef);
return (
<div ref={ targetRef } onMouseDown={mousedown}></div>
)
}
Thanks for reading
That's one way you can implement a drag and reposition feature in your project.
If you learned something new from this, please leave a comment.
If you spotted a bug, have a question, a correction, or know a better way this can be done, please also leave a comment. I would love to learn from you.
Thanks for reading!