Adding Drag and Drop to JavaScript Apps
Tags: webdev, javascript, tutorial, beginners
Published: 2020-01-19 01:19:22

**Subscribe to my email list now at http://jauyeung.net/subscribe/**

**Follow me on Twitter at https://twitter.com/AuMayeung**

**Many more articles at https://medium.com/@hohanga**

In JavaScript, events are actions that happen in an app. They’re triggered by various things like inputs being entered, forms being submitted, changes in an element like resizing, or errors that happen when an app is running, etc.

We can assign event handlers to events so we can take perform an action when one is triggered. Events that happen to DOM elements can be handled by assigning an event handler to properties of the DOM object for the corresponding events. In this article, we will look at the `ondragstart` and `ondrop` event handlers.

ondragstart event
=================

The `ondragstart` property of an HTML element lets us assign an event handler for the `dragstart` event which is triggered when the user starts dragging an element or text selection. For example, if we want to tracking when an element has started to be dragged and when it’s dropped, we can write the following HTML code:

```html
<p id='drag-start-tracker'>
</p>
<div id='drag-box' draggable="true">
</div>
<div id='drop-zone'>
</div>
```

In the code above, we have a `p` element to show when something is dragged and the ID of the element that's being dragged. We have an element with the ID `drag-box` that's being dragged. Below that, we have a `div` with the ID `drop-`zone that will accept any element that is being dragged to be dropped in it. Then we can add the following CSS to style the HTML elements we added above:

```css
#drag-box {  
  width: 100px;  
  height: 100px;  
  background-color: red;  
}

#drop-zone {  
  width: 200px;  
  height: 200px;  
  background-color: purple  
}
```

We can see that `drag-box` is red and `drop-zone` is purple and that `drop-zone` is bigger than `drag-box`. Next, we can assign our own event handler function to the `ondragstart` property for the DOM object representing the `drag-box` element to track it when it’s being dragged and update our `drag-start-tracker` `p` element to show that `drag-box` is being dragged with the following code:

```javascript
const dragBox = document.getElementById('drag-box');
const dropZone = document.getElementById('drop-zone');
const dragStartTracker = document.getElementById('drag-start-tracker');
dragBox.ondragstart = (e) => {
  dragStartTracker.innerHTML = `Element with ID ${e.target.id} is being dragged.`;
};
dragBox.ondragend = (e) => {
  dragStartTracker.innerHTML = '';
  dropZone.appendChild(e.srcElement);
};
```

In the code above, we can see that ‘Element with ID drag-box is being dragged’ when the `drag-box` element is being dragged, and when we stop dragging the box and drop it into the `drop-zone` element, we should see that the text disappears and the `drag-box` element stays inside the `drop-zone` element. How it works is that when we first start dragging the `drag-box` element, the `dragstart` event will be fired and the `dragBox.ondragstart` will be called with the `DragEvent` object passed in, which has the `e.target.id` property that we reference to get the ID of the `drag-box` element.

When we release the mouse button when the `drag-box` is over the `drop-zone` , the event handler that we assigned to the `ondragend` event handler is called since the `dragend` event is triggered by releasing the mouse button, ending the dragging of the `drag-box` .

Inside the function, we have a `DragEvent` object passed in when the function is called and we can use the `srcElement` to get the DOM element object of the element being dragged, so we can use `appendChild` method of the `dropZone` object to append the `drag-box` element, which is what we get with the `srcElement` property to the `drop-zone` element.

ondrop event
============

We can set the `ondrop` property of a DOM element to handle the `drop` event for the element. The `drop` event is fired when an element or text selection is dropped into a valid drop target. For example, we can use it to make a `div` element that can be dragged to 2 different boxes and use the `ondrop` event handler to handle the dropping. First, we add the following HTML code to make our draggable `div` element and 2 `div` elements where we can drop the draggable `div` element into the following code:

```html
<div id='drag-box' draggable="true">
</div>
<div id='drop-zones'>
  <div id='drop-zone'>
  </div>
  <div id='drop-zone-2'>
  </div>
</div>
```

Then we can add some CSS code to style the `div` elements with the following code:

```css
#drag-box {
  width: 100px;
  height: 100px;
  background-color: red;
}

#drop-zone {
  width: 200px;
  height: 200px;
  background-color: purple
}

#drop-zone-2 {
  width: 200px;
  height: 200px;
  background-color: green
}

#drop-zones {
  display: flex;
}
```

In the code above, we make the `drop-zone` `div` elements side by side by add a `div` with the ID `drop-zones` to contain the 2 `div` elements inside. We use the `display: flex` CSS code to display `drop-zone` and `drop-zone-2` `div` elements side by side. Then we change the background color of each div so we can distinguish them. Next, we add the JavaScript code to handle the dragging of the `drag-box` `div` elements and the dropping of it into either of the `drop-zone` elements with the with `ondrop` event handler that we define with the following code:

```javascript
const dragBox = document.getElementById('drag-box');
dragBox.ondragstart = (e) => {
  e
    .dataTransfer
    .setData('text/plain', event.target.id);
};
document.ondragover = (e) => {
  e.preventDefault();
};
document.ondrop = (e) => {
  const id = e
    .dataTransfer
    .getData('text');
  e.srcElement.appendChild(document.getElementById(id));
}
```

The code above works by handling the `ondragstart` event handler to get the ID of the element that’s being dragged. The `ondragstart` handler is called when users start dragging the `drag-box` `div` . Inside the `ondragstart` event handler function that we defined, we called the `e.dataTransfer.setData` method to set the `'text'` attribute of the `DataTransfer` object, which we need later when we’re dropping the `drag-box` inside one of the `drop-zone` or `drop-zone-2` `div` elements. It’s very important that we have:

```javascript
document.ondragover = (e) => {  
  e.preventDefault();  
};
```

This prevents the `ondragover` event handler from handling the event since once it’s handled with that event handler, then the `drop` event won’t be fired, and our `ondrop` event handler won’t be run. With that out of the way, we can define our `ondrop` event handler and then assign it to the `document.ondrop` property to handle the `document`’s `drop` event.

The event handler function has an `e` parameter which is a `DragEvent` object, which has some useful properties that we can use to handle the dropping of our `drag-box` element. Inside that event handler, we get the ID of the element that we’re dragging by calling the `e.dataTransfer.getData` method with the `'text'` string to get the ID of the element that we’re dragging.

Then we can use the `srcElement` property of the `e` object to get the DOM element of which our `drag-box` `div` is being dropped and call `appendChild` on it with the `document.getElementById(id)` argument, where `id` should be `'drag-box'` since that’s what should return from `e.dataTransfer.getData(‘text’);` since we set the ID of the `drag-box` element in the `dragBox.ondragstart` event handler.

Wrap Up
=======

The `ondragstart` and `ondrop` properties are very useful for making drag and drop features in our web page. The `ondragstart` property lets us assign an event handler for the `dragstart` event, which is triggered when the user starts dragging an element or text selection. We can set the `ondrop` property of a DOM element to handle the `drop` event for the element. The `drop` event is fired when an element or text selection is dropped into a valid drop target.

Note that we have made set an event handler function for the `ondragover` property of `document` and call `e.preventDefault()` inside the function to prevent the `ondragover` event handler from handling the `dragover` event, which stops the `drop` event from triggering. With that out of the way, we can assign an event handler to the `ondrop` property to append the draggable element as a child to the drop target element.