Creating a dropzone to enable drag and drop file upload
7 mins read
This tutorial will show how to enable a particular div (or any other tag) on a webpage to accept files that are dropped on them.
We all have encountered websites that allow us to upload files (mostly images) to their servers by directly dragging the file from some application (mainly file explorer of the OS) to a desginated area on the web page. This a replacement of the good old <input type="file" /> elements inside forms. Drag and drop is an HTML5 standard.
Browser support
- All of the modern browsers fully support drag and drop HTML5 API except IE (partially supported).
Getting started
As Drag n Drop is a new feature, we will also implement a fallback method to add support to older browsers so that users can upload files regardless of drag and drop is supported by their browsers or not.
We will create a function that will accept a DOM node and a callback function that is passed the list of files.
-
The signature of the function will be
makeDroppable(element, callback). -
Inside the
makeDroppablefunction,- We will first create an ‘input’ element of type
file. - Set its display to none so that it is not visible on the page.
- Add a listener to its
changeevent that will call the functiontriggerCallbackdiscussed further - Append it to the
elementprovided. - This is to implement a fallback method in browsers that do not support drag n drop. This will also provide an additional functionality that the users can click the
elementto add files if they want, instead of drag n drop.
- We will first create an ‘input’ element of type
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('multiple', true);
input.style.display = 'none';
input.addEventListener('change', triggerCallback);
element.appendChild(input);Now, we will add listeners to the element.
- The
dragoverevent:- This event is called when files are being dragged over the
elementand are yet to be dropped. - We call the event’s
preventDefaultmethod to prevent the browser from triggering its default behavior, i.e, it will try to open the file directly. - We call
stopPropagationmethod to prevent the event from bubbling up the DOM tree (this will prevent the triggering ofdragoverevent of any of the parent ofelement). - To add an effect to notify users that the
elementcan accept files, we will add the classdragoverto it that will have a slight different styling (like background color).
- This event is called when files are being dragged over the
element.addEventListener('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.add('dragover');
});- The
dragleaveevent:- This event is fired when something was being dragged on the
elementbut has been taken out instead of being dropped. - We call both the
preventDefaultandstopPropagationmethod as indragoverfor the same reasons. - To notify that the files being dragged has been removed, we remove the class that we added in the
dragoverevent so thatelementcan return to its initial styling.
- This event is fired when something was being dragged on the
element.addEventListener('dragleave', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.remove('dragover');
});- The
dropevent:- This event is fired when the files being dragged are finally dropped on the
element. - We call both the
preventDefaultandstopPropagationmethod as above. - We will then remove the
dragoverclass to return theelementto its inital style. - Now we call the
triggerCallbackfunction to handle the files.
- This event is fired when the files being dragged are finally dropped on the
element.addEventListener('drop', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.remove('dragover');
triggerCallback(e);
});- The
clickevent:- Since the
inputelement that we previously created is hidden on the page, we will addclickevent to theelementso that we can trigger the file chooser window to allow users to choose files by browsing their file explorer instead of dragging and dropping. - We set the value of
inputto null. - Then we call the
input’sclickmethod to open the file chooser.
- Since the
element.addEventListener('click', function() {
input.value = null;
input.click();
});- The
triggerCallbackfunction:- This function handles both the dropped files and the files selected through file chooser window.
- We first create a variable
filesthat will have the list of files chosen and will be passed to thecallbackprovided. - Then we check if the event that called this function has a
dataTransferobject or not. - If it has, that means the files were selected by dropping them on
element. We assign thee.dataTransfer.filesto thefilesvariable. - If there is no
dataTransferobject, that means the files were selected through the file chooser window. So we assigne.target.filesto thefilesvariable. - Now we pass the
filesvariable to thecallbackfunction provided. - The
filesvariable passed to thecallbackis an array ofFileobjects. EachFileobject has the following main properties:lastModified: Integer timestampname: The name of the file.size: Size of file in bytes.type: Mime-type of the file. (For ex: image/png for png files)
function triggerCallback(e) {
var files;
if(e.dataTransfer) {
files = e.dataTransfer.files;
} else if(e.target) {
files = e.target.files;
}
callback.call(null, files);
}Full code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
function makeDroppable(element, callback) {
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('multiple', true);
input.style.display = 'none';
input.addEventListener('change', triggerCallback);
element.appendChild(input);
element.addEventListener('dragover', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.add('dragover');
});
element.addEventListener('dragleave', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.remove('dragover');
});
element.addEventListener('drop', function(e) {
e.preventDefault();
e.stopPropagation();
element.classList.remove('dragover');
triggerCallback(e);
});
element.addEventListener('click', function() {
input.value = null;
input.click();
});
function triggerCallback(e) {
var files;
if(e.dataTransfer) {
files = e.dataTransfer.files;
} else if(e.target) {
files = e.target.files;
}
callback.call(null, files);
}
}
Usage:
We use the makeDroppable function like this:
- First create a
div(or any other) element:<div class="droppable">Drop your files here.</div>- Add style to the
div:.droppable { background: #08c; color: #fff; padding: 100px 0; text-align: center; }
- Create another class
dragoverthat will override the background of.droppable..droppable.dragover { background: #00CC71; }
- Call the
makeDroppable:
var element = document.querySelector('.droppable');
function callback(files) {
// Here, we simply log the Array of files to the console.
console.log(files);
}
makeDroppable(element, callback);Uses:
This implementation can be used for several purposes:
- Showing a preview of image files (or videos) to the users
- Upload the file list to the server through ajax call.
- Read the files on the browser itself using
FileReader(a topic for another tutorial).
Uploading the files through ajax (jQuery.ajax for simplicity)
The callback function that we defined earlier simply logs the FileList to console. We can modify that function to upload the dropped/selected files to the server.
var element = document.querySelector('.droppable');
function callback(files) {
var formData = new FormData();
formData.append("files", files);
$.ajax({
url: '/server_upload_url',
method: 'post',
data: formData,
processData: false,
contentType: false,
success: function(response) {
alert('Files uploaded successfully.');
}
});
}
makeDroppable(element, callback);