More articles

Drag And Drop Image Upload In JavaScript

Written by
Filed under
Published on
Modified on

File Uploads have yet to really catch up with the times and with technology. Many reasons for this. Security being a major one. It's an open door between the outside world and a server. And we can't just let any old file through to wreak havoc, if havoc is what it's there to wreak. So today I will be going over how to implement a file drag and drop module on your sites.

It's a somewhat involved process, and for sake of momentum I will focus on just the new standards that will make this happen, and I will leave out any compatability code.

Overview

The following will walk you through adding the ever so popular drag and drop file upload feature that we see on many a site. This example will only work on an HTML 5 compliant browser. However, you can easily detect if the browser supports said feature by checking if any of the drag events are supported.

Create a drop zone

First things first, we'll want to set up a drop zone for our files. This will be a pre-determined area somewhere on your site in which users will be able to drag files to. You'll want to make sure that it is designed in a way that will immediately tell the user that it is an area meant for dragging content into. Here's an example of a drop zone that I use on some of my sites.

Drag your file right over here!

It's quick and to the point, and it gives users plenty of room to drag their files into.

Tip #1: Don't give users a tiny area to drop files into

Style the drop zone

Feel free to use the following classes to style your dropzone.


.drag-drop{
    width: 100%;
    /* height: 100px; */
    background-color: #1caff6;
    margin-top: 30px;
    border-radius: 10px;
    border: dashed 2px white;
    color: white;
    text-align: center;
    padding-top: 40px;
    padding-bottom: 40px;
    font-size: 14pt;
    transition: .5s background-color, .5s color;
    height: 100px;
    font-family:inherit;
}

.drag-drop.dragover{
    background-color: #0e384c;
    color: white;
}

.drag-drop.uploading{
    background-color: #0e384c;
    color: white;
}

The dragover and uploading classes will be dynamically added during the corresponding event handlers in the JavaScript down below.

Setup the form

We will use a single input element setting the type to file. To read more about the File API, you can check out the Mozilla Developer Network page. The important parts to remember for this post however are as follows. You'll want your input form to look something like the following:


<form id="drag_files" class="drag-drop" method="post" action="" enctype="multipart/form-data" novalidate>
    <input type="file" name="files[]" id="files" multiple />
    <div class="drag-files-label">
        Drag your file right over here!
    </div>
</form>

A few things to notice in the above markup. Firstly, notice that I set the enctype of the form to multipart/form-data. Secondly, notice that I set the type of the input to file. This is an HTML 5 API and will not work on older browsers. Lastly notice the multiple specifier that we added to our input. That is also an HTML 5 property that allows our input to accept multiple files.

The drag events

There are a few events that will need to be handled in order to have a smooth and seemless process for our drag and drop. And we can start the process, by disabling the default behavior from each.


var form = document.getElementById("drag_files");
var input = form.querySelector('input[type="file"]');

window.addEventListener('load', function(){
    ['drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop'].forEach(function (event) {
         form.addEventListener(event, function (e) {
         // preventing the unwanted behaviours
                 e.preventDefault();
                 e.stopPropagation();
             });
         });
});

We'll want to let the user know when they arrive at the drop zone with their files. So for any event in which the mouse is dragging an item onto the zone, we'll want to add a 'dragover' class to our main form.


['dragover', 'dragenter'].forEach(function (event) {
     form.addEventListener(event, function () {
         form.classList.add('dragover');
     });
 });

['dragleave', 'dragend', 'drop'].forEach(function (event) {
    form.addEventListener(event, function () {
        form.classList.remove('dragover');
    });
});

Next up, we'll want to handle the actual drop event.


var droppedFiles;

form.addEventListener('drop', function (e) {
    droppedFiles = e.dataTransfer.files; // the files that were dropped

    if (droppedFiles.length > 0)
    {
        form.querySelector(".drag-files-label").innerHTML = droppedFiles[0].name;

        // optional - submit the form on drop
        var event = document.createEvent('HTMLEvents');
        event.initEvent('submit', true, false);
        form.dispatchEvent(event);
    }
});

The drop event provides us with the DataTransfer object, which further gives us the list of File objects that were dropped. For the sake of the example, I've only taken the name of the first file and added it to the dropzone. If you so wanted, you could submit the form on drop, which would begin the upload process as soon as your mouse was de-clicked.

Because we have all of our files stored in the droppedFiles object, we can easily push this data to the form. Whether you want to submit the form immediately, or later on in the process, you'll want to use the following method to do so.


     form.addEventListener('submit', function (e) {
         if (form.classList.contains('uploading'))
             return false;

             form.classList.add('uploading');
             e.preventDefault();

             // gathering the form data
             var ajaxData = new FormData(form);
             if (droppedFiles) {
                 Array.prototype.forEach.call(droppedFiles, function (file) {
                     ajaxData.append(input.getAttribute('name'), file);
                 });
             }

For each file that is stored in our droppedFiles object, we'll want to add those to a new formData object, of which you can read more about here. Next up, we're just going to create a standard Ajax request and send our form data along with it.


             // ajax request
             var ajax = new XMLHttpRequest();
             ajax.open(form.getAttribute('method'), form.getAttribute('action'), true);

             ajax.onload = function () {
                 form.classList.remove('uploading');
                 if (ajax.status >= 200 && ajax.status < 400) {
                    // do what you will :)
                 }
                 else {
                     alert('Error. Please, contact the webmaster!');
                 }
             };

             ajax.send(ajaxData);
     });

Feel free to customize the code anyway that you wish, and if you found it useful, feel free to send me a message as well. The full source is down below for your copy and paste pleasure.

View full source
Walter G. is a software engineer, startup co-founder, former CTO of several tech companies and currently teaches programming for a coding bootcamp. He has been blogging for the past 5 years and is an avid BMX rider, bio-hacker and performance enthusiast.
If you read this far, then I hope you enjoyed this post and found it useful! Consider adding to my daily coffee intake to continue to provide better and more helpful articles in the future!
Maybe later

Discussion / Comments / Questions

No messages posted yet

Add a comment

Send me your weekly newsletter filled with awesome ideas
Post comment