I got to work on a cool project last week where I learned a bunch of new things. For one part of the project I got to explore the HTML Drag and Drop API. This is the interface that allows the common ‘drag and drop’ functionality that is common on many web apps today.

The interface itself is dead simple and easy to use. It provides native event handlers like ondragenter, ondragover and ondrop, making it easy to customize drag and drop functionality.

Here’s a basic demo using a single HTML file for readability.

Let’s start with the usualy HTML cruft and a basic div with some inline styles applied.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <div
      id="dropzone"
      style="min-height: 250px; border: 5px dashed blue">
      <h1>open developer tools console and drop content here</h1>
    </div>
  </body>
</html>

Next, we stub out some javascript functions to handle the drag-and-drop events (same ones we mentioned earlier: ondragenter, ondragover and ondrop). Make sure to pass the native event to each of these functions.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <div
      id="dropzone"
      style="min-height: 250px; border: 5px dashed blue"
      ondragenter="handleDragEnter(event)"
      ondragover="handleDragOver(event)"
      ondrop="handleDrop(event)">
      <h1>open developer tools console and drop content here</h1>
    </div>
  </body>
</html>

Now we need to add a script tag and write some functions to handle the event.

For ondragenter and ondragover let’s just prevent the browser’s normal behavior by called stopPropagation and preventDefault on the native event.

For the ondrop we also want to prevent the native behavior with stopPropagation and preventDefault. But let’s console log the event and see what we have.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <div
      id="dropzone"
      style="min-height: 250px; border: 5px dashed blue"
      ondragenter="handleDragEnter(event)"
      ondragover="handleDragOver(event)"
      ondrop="handleDrop(event)">
      <h1>open developer tools console and drop content here</h1>
    </div>
  </body>
  <script>
    function handleDragEnter(event) {
      event.stopPropagation();
      event.preventDefault();
    }

    function handleDragOver(event) {
      event.stopPropagation();
      event.preventDefault();
    }

    function handleDrop(event) {
      event.stopPropagation();
      event.preventDefault();
      console.log(event)
    }
  </script>
</html>

Nice. it looks like a DragEvent based on the console output.

We can peel off a bunch of useful stuff from this event.

The DragEvent has a dataTransfer object, which itself contains a files method. The files methods yields a FileList object which we can then use to access the files from the drop event.

For a quick example let’s just grab some meta data off the file(s) and replace our “drop zone” message with the file data.

(warning…this is some very gross code but that’s generally the case with vanilla DOM api interactions)

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    <div
      id="dropzone"
      style="min-height: 250px; border: 5px dashed blue"
      ondragenter="handleDragEnter(event)"
      ondragover="handleDragOver(event)"
      ondrop="handleDrop(event)">
      <h1>open developer tools console and drop content here</h1>
    </div>
  </body>
  <script>
    function handleDragEnter(event) {
      event.stopPropagation();
      event.preventDefault();
    }

    function handleDragOver(event) {
      event.stopPropagation();
      event.preventDefault();
    }

    function handleDrop(event) {
      event.stopPropagation();
      event.preventDefault();
      console.log(event)

      var fileList = event.dataTransfer.files;
      var numFiles = fileList.length;
      var i = 0;

      while (i < numFiles) {
        var currentFile = fileList[i];

        var fileInfoDump = currentFile.name + currentFile.size + currentFile.type;

        document.getElementById('dropzone').innerHTML += fileInfoDump;

        i += 1;
      }
    }
  </script>
</html>

A quick next step would be to instantiate a new FileReader() to process the files for display, uploading, etc. More on that another time.