12 minutes read

In real life, we often move objects from place to place. So, what if we make our website more realistic then and let the users interact with the elements on the page and move them around? Fortunately, the HTML5 Drag and Drop API (DnD) allows us to do just that.

In this topic, you'll learn how to use standard HTML Drag and Drop methods to make elements on the page more interactive and familiar to the user.

Make an element draggable

By default, most elements cannot move on the page. To fix this, let's add the draggable attribute:

<div draggable="true">Drag me</div>

It's worth noting that elements such as images, links, and selected texts are draggable by default. You can check this by selecting some text and, for example, dragging it into the search box in the site header. You may notice that elements that can be dragged by default, or that have the draggable attribute, remain in place, while their phantom image is dragged instead.

Start dragging

The dragstart event informs about the start of the drag. You can put the code in the event handler that will be responsible for how the source element changes and set the data to be dragged. The DataTransfer object is responsible for setting the data. It is because of the properties of this object that data can be moved or copied, or a link can be created between the original position and the reset location.

Let's use the effectAllowed = "move" to allow our element to move. The effectAllowed property can also have other values, such as copy, link, all, and so on. To set the data, use the setData method of the DataTransfer object. As parameters let's pass the "text/plain" and the element id.

<div id="draggable" draggable="true" ondragstart="dragStartHandler(event)">Drag me</div>

<script>
  function dragStartHandler(event) {
    event.dataTransfer.effectAllowed = "move";
    event.dataTransfer.setData("text/plain", event.target.id);
  }
</script>

The DataTransfer object along with the DragEvent interface is the basis of the drag-and-drop operation. You can read more about it and all its properties in the documentation.

Target element

Let's add an element that will be a drag target: <div id="target">Target Area</div>. By default, items cannot be dropped anywhere. To allow resetting and prevent default events, such as a link jump, let's call event.preventDefault() for the dragover.

<div id="target" ondragover="dragOverHandler(event)">Target Area</div>

<script>
  function dragOverHandler(event) {
    event.preventDefault();
  }
</script>

Now let's add some styles to improve the user experience.

<div class="draggable" draggable="true" ondragstart="dragStartHandler(event)">
  Drag me
</div>
<div
  id="target"
  class="target"
  ondragover="dragOverHandler(event)"
  ondragenter="dragEnterHandler(event)"
  ondragleave="dragLeaveHandler(event)"
>
  Target Area
</div>

<!-- Add some styles -->
<style>
  .draggable {
    width: fit-content;
    padding: 2px 10px;
    border-radius: 4px;
    background: #96b38a;
    color: #333;
    cursor: move;
  }
  .target {
    padding: 10px;
    margin-top: 15px; 
    width: 250px;
    height: 100px;
    text-align: center;
    border-radius: 4px;
    border: 2px solid #ccc;
    color: #333;
  }
  .hovered {
    border: 2px dashed #ccc;
  }
</style>

<script>
  // Select the target element by id
  const targetItem = document.getElementById("target");
  
  function dragStartHandler(event) {...}
  
  function dragOverHandler(event) {...}
  
  // Add a 'hovered' class when the dragged element hits the target area
  function dragEnterHandler(event) {
    targetItem.classList.add('hovered');
  }
  
  // Remove the 'hovered' class when the dragged element leaves the target area
  function dragLeaveHandler(event) {
    targetItem.classList.remove('hovered');
  }
</script>

In the example above, we use the dragenter event for the target element to add a hovered class and apply styles. This is invoked when the dragged element crosses the boundary of the target element. The dragleave event is triggered when the dragged element moves out of the target element's boundary. We use it to remove the hovered class. We could add the class in the dragover handler, but this is not a good idea because the dragenter event is only triggered when the cursor is over the element, while the dragover event is triggered regularly as long as the dragged element is above the target.

Two green labelled square items floating around the target dotted bordered area

End dragging

It's time to use the data set in the first step in the dragstart event handler. Let's put this data into the target element using the drop event and the event.dataTransfer.getData('text/plain') method. Again, don't forget to call event.preventDefault() to prevent the default browser from processing the data (by default it opens as a link when dropped).

<div
  id="draggable"
  class="draggable"
  draggable="true"
  ondragstart="dragStartHandler(event)"
  ondragend="dragEndHandler(event)"
>
  Drag me
</div>
<div
  id="target"
  class="target"
  ondragover="dragOverHandler(event)"
  ondragenter="dragEnterHandler(event)"
  ondragleave="dragLeaveHandler(event)"
  ondrop="dropHandler(event)"
>
  Target Area
</div>

<style>
  <!-- The code from the previous example -->
</style>

<script>
  const targetItem = document.getElementById("target");

  // The code from the previous example

  function dropHandler(event) {
    event.stopPropagation();
    const data = event.dataTransfer.getData("text/plain");
    event.target.appendChild(document.getElementById(data));
    return false;
  }
  
  function dragEndHandler(event) {
    targetItem.classList.remove('hovered');
  }
</script>

So, we have defined target and draggable elements. In the dragStartHandler function, we have specified that the item can be moved, and we have saved its id for later use. In the dropHandler function, which will be called when the dragged element reaches the target, we retrieved the previously saved id, found an element with that id, and placed it in the target. With the dragEnterHandler function we added a class that will be applied every time the dragged element crosses the target. When the dragged element leaves the target, the previously added class will be removed.

Regardless of whether the item has been dropped into the target area or the drag has been undone, it will trigger a dragend event. You can also specify the desired behavior in it, such as changing the item's color, depending on whether the drag was successful or not. In our example, we've removed the hovered class.

Conclusion

Some elements can be dragged by default. For others, you need to add the draggable="true" attribute. The dragstart, drag, and dragend events help us tell the browser what should happen when dragging begins, ends, and is in progress. The target element has dragenter, dragleave, dragover, and drop events, which are responsible for what will happen when the draggable and the target elements interact. The basic magic of drag and drop lies in the DataTransfer property, which every drag event has. This property allows you to specify what manipulations are possible on the dragged element, can store different data, and more. In the HTML5 specification, you can find a practical and simple tool to implement moving elements on the page.

18 learners liked this piece of theory. 8 didn't like it. What about you?
Report a typo