Simple Drag and Reposition in Vanilla JavaScript and React

Simple Drag and Reposition in Vanilla JavaScript and React

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!