How To Use HTML5 Drag And Drop

Introduction

The drag and drop API built into HTML5 is very simple for us to use, and what I'll do is have examples of very basic things, the minimum requirements that I'll meet, then I'll look at the syntax and some of the new capabilities that have been added to it.

What is Drag and Drop in HTML?

Drag is an action where the user can select draggable elements with the mouse and release them by releasing the mouse button.

HTML drag-and-drop interfaces enable applications to use drag-and-drop features in browsers.

We can customize which elements become draggable or droppable.

Drop Zone in HTML

We have an area here that has a bunch of elements that I can drag and drop, and we also have a drop zone. This is where I can put them, so I can click on them and drag them over.

I'm putting some content in the drop zone when I drop it. I can drag it, but if I release it somewhere else, it goes back to the origin. We can see it's a link. I dragged the link, so I am getting the link. If I drag the text. The drop zone contains a copy of the text and the file if I drag the image. A copy of the drop zone image is a ghosted version of the image that is being dragged and dropped.

<body>
  <header>
    <h1>Drag and Drop</h1>
  </header>
  <main>
    <section>
      <h2>Drag On</h2>
      <div class="cards">
        <div class="card draggable" draggable="true">
          <p>HELLO WORLD!</p>
        </div>
        <div class="card draggable" draggable="true">
          <a href="https://www.google.com/">Google Link</a>
        </div>
        <div class="card draggable" draggable="true">
          <img src="bful_color_flowers_08.jpg" alt="image 1" />
        </div>
        <div class="card draggable" draggable="true">
          <img src="bful_color_flowers_09.jpg" alt="image 2" />
        </div>
      </div>
    </section>
    <section class="drop">
      <h2>Dropp In'</h2>
      <div class="dropzone">&nbsp;</div>
    </section>
  </main>
  <footer>
    <p>&copy; 2023 </p>
  </footer>
  <script src="main.js"></script>
</body>

Drag and Drop

Drag and Drop

So this is the html I'm using. I've got my card section. This is where all the draggable stuff is, and here is my drop zone. It's just for CSS so I can detect it on the page. Nothing is required here about this name or anything like that. Here the class names are draggable. I am using this here. This is just for my CSS so that I can recognize this attribute. Although draggable is equally true here, it is something that we must have if we want to move an element from one place to another in our HTML to be able to do so. We just need to set draggable to true.

Define the drag's data 

Script a DOM content-loaded event that starts after the HTML has loaded. We should have the three necessary event listeners, and I can go and get everything with the class drop zone and listeners on those. But it's easier if I just put them on the body element, then inside my function, I can see that the thing that is being dragged or dropped is one of those draggable or droppable items.

document.addEventListener('DOMContentLoaded', () => {
    //required event listeners
    document.body.addEventListener('dragstart', handleDragStart); //for draggable
    document.body.addEventListener('drop', handleDrop); //for dropzone
    document.body.addEventListener('dragover', handleOver); //for dropzone
    //optional but useful events
    document.body.addEventListener('mousedown', handleCursorGrab);
    document.body.addEventListener('dragenter', handleEnter);
    document.body.addEventListener('dragleave', handleLeave);
    //set up draggable things (non-ios)
    imgElement.src = './img/dragon-3.jpg';
    document.querySelector('footer>p').appendChild(imgElement);
    dragElement.textContent = 'Wheeeee';
    dragElement.classList.add('wheeeee');
    document.querySelector('footer>p').appendChild(dragElement);
});

So dragstart is when we have clicked on an element and moved our mouse without releasing it or moving the trackpad. That is the dragstart event. This is the dragstart event. I dragged it into that drop zone, and then I dragged it out of the drop zone. Those are the other two events that are happening here, so dragstart. We've clicked, and we're starting to drag, or on a device we've trapped, and we're starting to drag. Well, when we let it go here, I'm dragging; if I let it go here, it's a drop. If I come over here and I leave it there, now we go because my function says we're dropping it's at a place I care about, so I'm writing this, it's not that there's not a drop event somewhere else, it's just that the drop event here, we go Happening in an area on my page that I have designated as my drop zone.

"div with class draggable" is the box I am using to move the paragraphs, anchor, and image inside it.

Creating some content to transport so that the DragStart event has access to a property called DataTransfer, and the DataTransfer object is the thing that will contain any information I want to bring up when I drag something.

​function handleDragStart(ev) {
    //user started to drag a draggable from the webpage
    let obj = ev.target;
    if (!obj.closest('.draggable')) return;
    if (obj.classList.contains('draggable')) {
        obj = obj.firstElementChild;
    }
    myData.tag = obj.tagName;
    myData.text = obj.textContent ? obj.textContent : obj.alt ? obj.alt : '';
    myData.url = obj.href ? obj.href : obj.src ? obj.src : '';
    myData.timestamp = Date.now();
    let data = JSON.stringify(myData);
    ev.dataTransfer.setData('application/json', data);
    obj.setAttribute('data-ts', myData.timestamp);
    let dataList = ev.dataTransfer.items;
    for (let i = 0; i < ev.dataTransfer.items.length; i++) {
        let item = ev.dataTransfer.items[i];
    }
}​

How to Handle the drop effect?

Now, when I drop it, when my handle drop function fires here, I will make sure that we leave it on the drop zone; in that case, I need to prevent the default. In this case, there is a need to stop default behavior, which tells the browser you do not do it normally, as if someone is dragging something from outside the page or if someone has any pages but something has been dragged from somewhere.

When I drag it, that's the piece of information copied over, so it's not very useful at this point, but this is the basic functionality. We're dragging things over, and we can use set data to save some data. We use to get data to retrieve that information.

function handleDrop(ev) {
    let dropzone = ev.target;
    if (!dropzone.classList.contains('dropzone')) return;
    ev.preventDefault();
    // console.log('DROP', ev.dataTransfer);
    // let data = ev.dataTransfer.getData('text/plain');
    let data = JSON.parse(ev.dataTransfer.getData('application/json'));
    let draggable = document.querySelector(`[data-ts="${data.timestamp}"]`);
    let clone = draggable.cloneNode(true);
    dropzone.append(clone);
    draggable.remove();
    // dropzone.textContent += data;
    dropzone.classList.remove('over');
    let len = ev.dataTransfer.items.length;
    for (let i = 0; i < len; i++) {
        let item = ev.dataTransfer.items[i];
        if (item.kind === 'string' && item.type.match('^text/html')) {
            //i got an html element
        }
        if (item.kind === 'string' && item.type.match('^application/json')) {
            //same as before... except the method getAsString
            item.getAsString((json) => {
                let data = JSON.parse(json);
                console.log('timestamp was', data.timestamp);
            })
        }
    }

If we want, we can write that information out on the page. I'm also removing a class called over, which I added right here in my handle over. This was the other event handled inside there. I'm adding the class over, and all that does is add a CSS class, so when I move over this, you can see the gold border that appears when I go back on, I'm changing the border colour just so I get some visual indication, or the user gets some visual indication this is a drop zone, this is a place where we can drop our elements.

function handleOver(ev) {
    //fires continually
    let dropzone = ev.target;
    if (!dropzone.classList.contains('dropzone')) return;
    ev.preventDefault();
    // dropzone.classList.add('over'); //can do this in handleEnter
    // console.log('dragover dropzone');
}
//optional but useful visual stuff...
function handleCursorGrab(ev) {
    let obj = ev.target;
    if (!obj.closest('.draggable')) return;
    obj.style.cursor = 'grabbing'; //close the hand
}

function handleEnter(ev) {
    //fires once
    let dropzone = ev.target;
    if (!dropzone.classList.contains('dropzone')) return;
    ev.preventDefault();
    dropzone.classList.add('over');
    // console.log('dragenter dropzone')
}

function handleLeave(ev) {
    let dropzone = ev.target;
    if (!dropzone.classList.contains('dropzone')) return;
    ev.preventDefault();
    dropzone.classList.remove('over');
    // console.log('dragleave dropzone');
}

Best practices for using drag and drop in HTML

Ensure accessibility- Make sure that your drag-and-drop interface is usable by screen readers and other assistive technology, as well as by all other users. Offer different ways to move things, like buttons or keyboard shortcuts.
Improve performance- Drag and drop may be resource intensive. Therefore, it's critical to improve the performance of your code. Reduce the quantity of data that has to be sent between the client and server by using efficient methods for managing huge numbers of objects.
Use visual signals- Make it obvious where and when an object can be dropped through the use of visual clues. This can be done by altering the object's look, adding a drop zone indication, or highlighting the drop position with animation.
Test on several platforms- Try out your drag-and-drop user interface on multiple computers, smartphones, tablets, and other mobile devices. Make sure that it functions properly across a range of input modalities and screen sizes.
When a user drags and drops an object, give them feedback. This could take the form of a confirmation message or a visual cue that the action was successful.

Conclusion

The drag-and-drop API is really easy to use, and as we may already know, it allows us to drag and drop any elements. It is also commonly used to allow support for dragging and dropping files from the operating system for file upload forms. During drag operations, several event types are fired, and some events might fire many times, such as the drag, dragend, dragenter, dragleave, dragover, dragstart, and drop events.

Reference