236

These days we can drag & drop files into a special container and upload them with XHR 2. Many at a time. With live progress bars etc. Very cool stuff. Example here.

But sometimes we don't want that much coolness. What I'd like is to drag & drop files -- many at a time -- into a standard HTML file input: <input type=file multiple>.

Is that possible? Is there some way to 'fill' the file input with the right filenames (?) from the file drop? (Full filepaths aren't available for file system security reasons.)

Why? Because I'd like to submit a normal form. For all browsers and all devices. The drag & drop is just progressive enhancement to enhance & simplify UX. The standard form with standard file input (+ multiple attribute) will be there. I'd like to add the HTML5 enhancement.

edit
I know in some browsers you can sometimes (almost always) drop files into the file input itself. I know Chrome usually does this, but sometimes it fails and then loads the file in the current page (a big fail if you're filling out a form). I want to fool- & browserproof it.

shasi kanth
  • 6,987
  • 24
  • 106
  • 158
Rudie
  • 52,220
  • 42
  • 131
  • 173

15 Answers15

162

The following works in Chrome and FF, but i've yet to find a solution that covers IE10+ as well:

// dragover and dragenter events need to have 'preventDefault' called
// in order for the 'drop' event to register. 
// See: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Drag_operations#droptargets
dropContainer.ondragover = dropContainer.ondragenter = function(evt) {
  evt.preventDefault();
};

dropContainer.ondrop = function(evt) {
  // pretty simple -- but not for IE :(
  fileInput.files = evt.dataTransfer.files;

  // If you want to use some of the dropped files
  const dT = new DataTransfer();
  dT.items.add(evt.dataTransfer.files[0]);
  dT.items.add(evt.dataTransfer.files[3]);
  fileInput.files = dT.files;

  evt.preventDefault();
};
<!DOCTYPE html>
<html>
<body>
<div id="dropContainer" style="border:1px solid black;height:100px;">
   Drop Here
</div>
  Should update here:
  <input type="file" id="fileInput" />
</body>
</html>

You'll probably want to use addEventListener or jQuery (etc.) to register your evt handlers - this is just for brevity's sake.

Jacob van Lingen
  • 8,989
  • 7
  • 48
  • 78
jlb
  • 19,090
  • 8
  • 34
  • 65
  • 5
    Waaaaaaaat! That works!? That's **exactly** what I was looking for. Didn't work 2 years ago. Awesome! Of course it doesn't work in IE =) The important question: is there reliable feature detection?, so you can hide the dropzone in IE, bc it won't work. – Rudie Aug 17 '16 at 09:57
  • D'oh, a bit late then :) Right now im just using simple user agent checks in JS. Of course you have to test for `MSIE `, `Trident/` (IE11) and `Edge/` (IE12)... – jlb Aug 17 '16 at 12:56
  • FF 48.0.2 (Mac) throws "TypeError: setting a property that has only a getter" at line `fileInput.files = evt.dataTransfer.files;`. Safari and Chrome however both work fine. – Risadinha Oct 26 '16 at 10:40
  • 2
    This example doesn't work on firefox 45 on linux, but it works for me on chrome. I don't get any console errors, it simply doesn't show that any file was dropped. – Bryan Oakley Feb 01 '17 at 15:19
  • Just spent hours trying to get dropzone js to work in an existing form. Copied and pasted this simple answer and works as expected right away. Thanks! Wondering if you have any idea how to make it so you can drag/click multiple files separately and still keep the previous files? I mean if you drag one file and then drag another, it clears the first. Would be perfect if you could keep adding. – nick Apr 12 '17 at 21:23
  • @nick unfortunately that's not possible with -- sorry :( – jlb Apr 13 '17 at 15:13
  • 1
    actually I made a post to try and find a solution but figured out for myself. Pretty simple change, just fileInputs[index] = ... to pass the file data to a particular input and then call a function showNext to add a new input http://stackoverflow.com/a/43397640/6392779 – nick Apr 13 '17 at 16:46
  • Linux / Chrome Version 59.0.3071.115 (Official Build) (64-bit) -- Works! Linux / FF 54.0 -- Does nothing. – henryC Jul 14 '17 at 10:30
  • I had to apply `evt.preventDefault(); e.stopPropagation()` to all of the following to make this work: `drag dragstart dragend dragover dragenter dragleave drop` – LinusGeffarth Jan 25 '18 at 14:10
  • This solution doesn't trigger the `change` event on the input under Firefox, so you have to [manually trigger](https://stackoverflow.com/a/23612498/1494454) it: `fileInput.dispatchEvent(new Event('change'))`. I have FF 58. – totymedli Apr 18 '18 at 06:27
  • 2
    Thanks, works! I've created working link https://jsfiddle.net/abratashov/n42ohkr3/2/ – Oleksandr Bratashov Jun 23 '21 at 11:30
  • 3
    @SashaB. no, the fiddle doesn't work in Firefox 91.0.2, Win10. Opens the image instead in the tab. – Fanky Sep 01 '21 at 13:22
  • 2
    It throw an Error: { "message": "Uncaught TypeError: Failed to execute 'add' on 'DataTransferItemList': parameter 1 is not of type 'File'.", "filename": "https://stacksnippets.net/js", "lineno": 35, "colno": 12 } – Caleb Liu Jul 06 '22 at 12:12
  • 1
    I was getting the same error, it's because of this line `dT.items.add(evt.dataTransfer.files[3]);`, it only works with 4+ files – Alphka Jan 11 '23 at 21:16
51

I made a solution for this.

$(function () {
    var dropZoneId = "drop-zone";
    var buttonId = "clickHere";
    var mouseOverClass = "mouse-over";

    var dropZone = $("#" + dropZoneId);
    var ooleft = dropZone.offset().left;
    var ooright = dropZone.outerWidth() + ooleft;
    var ootop = dropZone.offset().top;
    var oobottom = dropZone.outerHeight() + ootop;
    var inputFile = dropZone.find("input");
    document.getElementById(dropZoneId).addEventListener("dragover", function (e) {
        e.preventDefault();
        e.stopPropagation();
        dropZone.addClass(mouseOverClass);
        var x = e.pageX;
        var y = e.pageY;

        if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
            inputFile.offset({ top: y - 15, left: x - 100 });
        } else {
            inputFile.offset({ top: -400, left: -400 });
        }

    }, true);

    if (buttonId != "") {
        var clickZone = $("#" + buttonId);

        var oleft = clickZone.offset().left;
        var oright = clickZone.outerWidth() + oleft;
        var otop = clickZone.offset().top;
        var obottom = clickZone.outerHeight() + otop;

        $("#" + buttonId).mousemove(function (e) {
            var x = e.pageX;
            var y = e.pageY;
            if (!(x < oleft || x > oright || y < otop || y > obottom)) {
                inputFile.offset({ top: y - 15, left: x - 160 });
            } else {
                inputFile.offset({ top: -400, left: -400 });
            }
        });
    }

    document.getElementById(dropZoneId).addEventListener("drop", function (e) {
        $("#" + dropZoneId).removeClass(mouseOverClass);
    }, true);

})
#drop-zone {
    /*Sort of important*/
    width: 300px;
    /*Sort of important*/
    height: 200px;
    position:absolute;
    left:50%;
    top:100px;
    margin-left:-150px;
    border: 2px dashed rgba(0,0,0,.3);
    border-radius: 20px;
    font-family: Arial;
    text-align: center;
    position: relative;
    line-height: 180px;
    font-size: 20px;
    color: rgba(0,0,0,.3);
}

    #drop-zone input {
        /*Important*/
        position: absolute;
        /*Important*/
        cursor: pointer;
        left: 0px;
        top: 0px;
        /*Important This is only comment out for demonstration purposes.
        opacity:0; */
    }

    /*Important*/
    #drop-zone.mouse-over {
        border: 2px dashed rgba(0,0,0,.5);
        color: rgba(0,0,0,.5);
    }


/*If you dont want the button*/
#clickHere {
    position: absolute;
    cursor: pointer;
    left: 50%;
    top: 50%;
    margin-left: -50px;
    margin-top: 20px;
    line-height: 26px;
    color: white;
    font-size: 12px;
    width: 100px;
    height: 26px;
    border-radius: 4px;
    background-color: #3b85c3;

}

    #clickHere:hover {
        background-color: #4499DD;

    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="drop-zone">
    Drop files here...
    <div id="clickHere">
        or click here..
        <input type="file" name="file" id="file" />
    </div>
</div>

The Drag and Drop functionality for this method only works with Chrome, Firefox and Safari. (Don't know if it works with IE10), but for other browsers, the "Or click here" button works fine.

The input field simply follow your mouse when dragging a file over an area, and I've added a button as well..

Uncomment opacity:0; the file input is only visible so you can see what's going on.

Richard Parnaby-King
  • 14,703
  • 11
  • 69
  • 129
BjarkeCK
  • 5,694
  • 5
  • 41
  • 59
  • That's why i added a button aswell^^ But yah your'e right. I wouln't use it eather... Or would i !? – BjarkeCK Oct 03 '12 at 18:23
  • I wish I knew how that is supposed to work... it seems all the drag/drop functions have to deal with adding the hover effect... but I really can't tell. Looks good in the fiddle, but I don't think I can use it since I need to support Internet Explorer – nmz787 Apr 02 '15 at 00:13
  • @nmz787 checkout this thread, you might find another solution there. http://stackoverflow.com/questions/1537223/change-cursor-type-on-input-type-file/9182787 – BjarkeCK Apr 02 '15 at 01:10
  • Actually I like it. And it could work for multiple files too, because JS could make any input 'fly' and keep others down, and dynamically add more. – Rudie Nov 20 '15 at 12:24
  • @BjarkeCK wouldn't it be easier to add `click` listener to `#clickHere` and just `.click()` hidden file input? I mean, a bit shorter and more readable code IMO. – Tithen-Firion Sep 19 '16 at 16:31
  • 1
    @PiotrKowalski I think that would potentially trigger a recursive call until the call stack overflows – John Sep 28 '16 at 12:08
  • @John you are right. My browser handles this well (stops after second `.click()` because file selection window is already open) but you can add `click` listener to file input and `e.stopPropagation()` should do the trick. – Tithen-Firion Sep 28 '16 at 13:06
  • 2
    I ended up using the style only. Making the input 100% width and height worked better than moving it around. – Eddie Mar 28 '17 at 04:35
  • For adding and removing **mouse-over** class of the drop-zone it would be better to use _dragenter_ and _dragleave_ events. – JeFf Apr 10 '17 at 12:10
  • 2
    Is there a way to get rid of the "no file chosen" which keeps hovering along with our mouse pointer? @BjarkeCK – Abhishek Singh Dec 24 '18 at 16:15
  • @BjarkeCK Thank you for this solution - I was wondering if you know a good way to make it so only the "or click here.." button displays but acts the same as the – Kameron Sep 14 '21 at 13:49
35

This is the "DTHML" HTML5 way to do it. Normal form input (which IS read only as Ricardo Tomasi pointed out). Then if a file is dragged in, it is attached to the form. This WILL require modification to the action page to accept the file uploaded this way.

function readfiles(files) {
  for (var i = 0; i < files.length; i++) {
    document.getElementById('fileDragName').value = files[i].name
    document.getElementById('fileDragSize').value = files[i].size
    document.getElementById('fileDragType').value = files[i].type
    reader = new FileReader();
    reader.onload = function(event) {
      document.getElementById('fileDragData').value = event.target.result;}
    reader.readAsDataURL(files[i]);
  }
}
var holder = document.getElementById('holder');
holder.ondragover = function () { this.className = 'hover'; return false; };
holder.ondragend = function () { this.className = ''; return false; };
holder.ondrop = function (e) {
  this.className = '';
  e.preventDefault();
  readfiles(e.dataTransfer.files);
}
#holder.hover { border: 10px dashed #0c0 !important; }
<form method="post" action="http://example.com/">
  <input type="file"><input id="fileDragName"><input id="fileDragSize"><input id="fileDragType"><input id="fileDragData">
  <div id="holder" style="width:200px; height:200px; border: 10px dashed #ccc"></div>
</form>

It is even more boss if you can make the whole window a drop zone, see How do I detect a HTML5 drag event entering and leaving the window, like Gmail does?

William Entriken
  • 37,208
  • 23
  • 149
  • 195
  • 2
    Good solution yet it does not work on IE < 10 because IE 9 and less does not support HTML5 files API :( – Develoger Dec 08 '13 at 02:04
  • 1
    This line: document.getElementById('fileDragData').value = files[i].slice(); is not needed, because it is superseded in the reader.onload function – kurdtpage Feb 15 '16 at 00:30
  • Here is another cute drag and drop application that does NOT involve file uploads. Linking just in case somebody wants to study more. https://codepen.io/anon/pen/MOPvZK?editors=1010 – William Entriken Nov 29 '17 at 00:05
  • 1
    The IE 10 solution is to degrade and only show the `input type=file` – William Entriken Nov 29 '17 at 00:07
  • Am I missing something, or do you just constantly overwrite the `.value` property with the most recent file, every time you iterate through the fore loop? – Kevin Burke Jan 04 '18 at 04:28
  • I spent two hours wondering why onload never fired. It's because you do: "reader.readAsDataURL(files[i]);" after the onload event instead of inside it. Since I didn't understand how any of this worked and typed out the code for myself I put your curly bracket after that readAs line instead of before it, which caused the issue. It's all because you didn't put your curly closing bracket in a nice spot. Please format your javascript code beautifully instead of succinctly. – TheRedstoneTaco Jun 28 '18 at 19:15
  • That's a good solution. Just wanted to suggest a small update which is related to when we decide to abort the drag, in the code above, the border stays green when it should return back to its previous state instead. I suggest to replace ondragend with ondragleave. – Zakaria Boukaddouss Oct 08 '22 at 12:44
30

For a native solution without any JS:

<div class="file-area">
    <input type="file">
    <div class="file-dummy">
        <span class="default">Click to select a file, or drag it here</span>
        <span class="success">Great, your file is selected</span>
    </div>
</div>

<style>
    .file-area {
        width: 100%;
        position: relative;
        font-size: 18px;
    }
    .file-area input[type=file] {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        opacity: 0;
        cursor: pointer;
    }
    .file-area .file-dummy {
        width: 100%;
        padding: 50px 30px;
        border: 2px dashed #ccc;
        background-color: #fff;
        text-align: center;
        transition: background 0.3s ease-in-out;
    }
    .file-area .file-dummy .success {
        display: none;
    }
    .file-area:hover .file-dummy {
        border: 2px dashed #1abc9c;
    }
    .file-area input[type=file]:valid + .file-dummy {
        border-color: #1abc9c;
    }
    .file-area input[type=file]:valid + .file-dummy .success {
        display: inline-block;
    }
    .file-area input[type=file]:valid + .file-dummy .default {
        display: none;
    }
</style>

Adapted from https://codepen.io/Scribblerockerz/pen/qdWzJw

Jonathan
  • 13,947
  • 17
  • 94
  • 123
  • 1
    For me, this is the coolest solution, No JS. Thanks for adding it here. I never knew the `` support this drag option natively! – Wajahath May 23 '21 at 05:59
  • 1
    Cool, only it seems input is `:valid` even when no file selected (FF) – Fanky Sep 01 '21 at 13:33
  • Oh it works when the input has `required` attribute. But I don't want the input required :) – Fanky Sep 02 '21 at 07:44
  • 1
    Finaly replacing with `.file-area input[type=file]:not([value=""]) + ...` but adding `jQuery( 'input[type=file]' ).change( function( e ) { this.defaultValue = this.value;} );` because DOM value attribute doesn't update otherwise. So not pure-css anymore. – Fanky Sep 02 '21 at 08:16
15

//----------App.js---------------------//
$(document).ready(function() {
    var holder = document.getElementById('holder');
    holder.ondragover = function () { this.className = 'hover'; return false; };
    holder.ondrop = function (e) {
      this.className = 'hidden';
      e.preventDefault();
      var file = e.dataTransfer.files[0];
      var reader = new FileReader();
      reader.onload = function (event) {
          document.getElementById('image_droped').className='visible'
          $('#image_droped').attr('src', event.target.result);
      }
      reader.readAsDataURL(file);
    };
});
.holder_default {
    width:500px; 
    height:150px; 
    border: 3px dashed #ccc;
}

#holder.hover { 
    width:400px; 
    height:150px; 
    border: 3px dashed #0c0 !important; 
}

.hidden {
    visibility: hidden;
}

.visible {
    visibility: visible;
}
<!DOCTYPE html>

<html>
    <head>
        <title> HTML 5 </title>
        <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.js"></script>
    </head>
    <body>
      <form method="post" action="http://example.com/">
        <div id="holder" style="" id="holder" class="holder_default">
          <img src="" id="image_droped" width="200" style="border: 3px dashed #7A97FC;" class=" hidden"/>
        </div>
      </form>
    </body>
</html>
Dipak
  • 6,532
  • 8
  • 63
  • 87
  • 2
    What does it show the user? Can you make a fiddle or online example? – Rudie Jul 01 '14 at 22:08
  • 1
    @Rudie please click run code snippet and drag-n-drop one image to view, it will show the preview of image dropped. – Dipak Jul 19 '17 at 14:22
13

This is what I came out with.

Using Jquery and Html. This will add it to the insert files.

var dropzone = $('#dropzone')


dropzone.on('drag dragstart dragend dragover dragenter dragleave drop', function(e) {
    e.preventDefault();
    e.stopPropagation();
  })

dropzone.on('dragover dragenter', function() {
    $(this).addClass('is-dragover');
  })
dropzone.on('dragleave dragend drop', function() {
    $(this).removeClass('is-dragover');
  })  
  
dropzone.on('drop',function(e) {
 var files = e.originalEvent.dataTransfer.files;
 // Now select your file upload field 
 // $('input_field_file').prop('files',files)
  });
input { margin: 15px 10px !important;}

.dropzone {
 padding: 50px;
 border: 2px dashed #060;
}

.dropzone.is-dragover {
  background-color: #e6ecef;
}

.dragover {
 bg-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<div class="" draggable='true' style='padding: 20px'>
 <div id='dropzone' class='dropzone'>
  Drop Your File Here
 </div>
 </div>
Lionel Yeo
  • 383
  • 4
  • 13
10

Easy and simple. You don't need create a new FormData or do an Ajax to send image. You can put dragged files in your input field.

osx users: maybe in osx you need unmaximize your browser to drag files. why? idk.

$dropzone.ondrop = function (e) {
    e.preventDefault();
    input.files = e.dataTransfer.files;
}

var $dropzone = document.querySelector('.dropzone');
var input = document.getElementById('file-upload');

$dropzone.ondragover = function (e) { 
  e.preventDefault(); 
  this.classList.add('dragover');
};
$dropzone.ondragleave = function (e) { 
    e.preventDefault();
    this.classList.remove('dragover');
};
$dropzone.ondrop = function (e) {
    e.preventDefault();
    this.classList.remove('dragover');
    input.files = e.dataTransfer.files;
}
.dropzone {
  padding: 10px;
  border: 1px dashed black;
}
.dropzone.dragover {
  background-color: rgba(0, 0, 0, .3);
}
<div class="dropzone">Drop here</div>
<input type="file" id="file-upload" style="display:none;">
GIA
  • 1,400
  • 2
  • 21
  • 38
6

In theory, you could add an element overlaying the <input/>, and then use it's drop event to capture the files (using the File API) and pass them to input files array.

Except that a file input is read-only. This is an old problem.

You can however, bypass the form control completely and upload via XHR (not sure about the support for that):

You could also use an element in the surrounding area to cancel the drop event in Chrome, and prevent the default behaviour of loading the file.

Dropping multiple files over the input already works in Safari and Firefox.

Ricardo Tomasi
  • 34,573
  • 2
  • 55
  • 66
  • 6
    Like I said in the question: I know XHR2 and I don't want to use it. I guess the iportant part: "the file input is read-only". That sucks... Cancelling the drop event isn't a bad idea! Not as good as I'd hoped, but probably the best. Dropping multiple files works in Chrome too btw. Chrome now also allows uploading directories. All very kewl and not helping my case =( – Rudie Nov 15 '11 at 13:02
5

I know some trick works in Chrome:

When dropping files into drop zone you get a dataTransfer.files object, that is a FileList type of object, that contains all the files you dragged. Meanwhile, <input type="file" /> element has the property files, that is the same FileList type object.

So, you can simply assign the dataTransfer.files object to the input.files property.

Mike Doe
  • 16,349
  • 11
  • 65
  • 88
Timur Gilauri
  • 824
  • 8
  • 13
  • 3
    Yes, it does these days. Not a trick. Very intentional. Also very intentionally very restricted. You can't add files to the list, or mutate the list at all. Dragging and dropping can remember files, and add onto them, but `input.files` can't =( – Rudie Feb 18 '17 at 11:24
3

For anyone who's looking to do this in 2018, I've got a much better and simpler solution then all the old stuff posted here. You can make a nice looking drag & drop box with just vanilla HTML, JavaScript and CSS.

(Only works in Chrome so far)

Let's start with the HTML.

<div>
<input type="file" name="file" id="file" class="file">
<span id="value"></span>
</div>

Then we'll get to the styling.

    .file {
        width: 400px;
        height: 50px;
        background: #171717;
        padding: 4px;
        border: 1px dashed #333;
        position: relative;
        cursor: pointer;
    }

    .file::before {
        content: '';
        position: absolute;
        background: #171717;
        font-size: 20px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 100%;
        height: 100%;
    }

    .file::after {
        content: 'Drag & Drop';
        position: absolute;
        color: #808080;
        font-size: 20px;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    }

After you've done this it already looks fine. But I imagine you'd like to see what file you actaully uploaded, so we're going to do some JavaScript. Remember that pfp-value span? That's where we'll print out the file name.

let file = document.getElementById('file');
file.addEventListener('change', function() {
    if(file && file.value) {
        let val = file.files[0].name;
        document.getElementById('value').innerHTML = "Selected" + val;
    }
});

And that's it.

Michael
  • 31
  • 2
  • I get a Uncaught TypeError: Cannot read property 'addEventListener' of null when i use this code - under Chrome - does it not work in latest versions of Chrome? – Fight Fire With Fire Jul 16 '18 at 22:08
  • It works fine for me in the latest version of Chrome. Make sure you use the right ID's – Michael Aug 01 '18 at 00:45
2

Few years later, I've built this library to do drop files into any HTML element.

You can use it like

const Droppable = require('droppable');

const droppable = new Droppable({
    element: document.querySelector('#my-droppable-element')
})

droppable.onFilesDropped((files) => {
    console.log('Files were dropped:', files);
});

// Clean up when you're done!
droppable.destroy();
Joel Hernandez
  • 1,817
  • 4
  • 18
  • 27
2

This is an improvement, bugfix, and modification of the example that William Entriken gave here. There were some issues with it. For example the normal button from <input type="file" /> didn't do anything (in case the user wanted to upload the file that way).

Notice: I am making a webapp that only I use, so this is only tested (and refined) for Firefox. I am sure though that this code is of value even if you develop for the crossbrowser situation.

function readFile(e) {
  var files;
  if (e.target.files) {
    files=e.target.files
  } else {
    files=e.dataTransfer.files
  }
  if (files.length==0) {
    alert('What you dropped is not a file.');
    return;
  }
  var file=files[0];
  document.getElementById('fileDragName').value = file.name
  document.getElementById('fileDragSize').value = file.size
  document.getElementById('fileDragType').value = file.type
  reader = new FileReader();
  reader.onload = function(e) {
    document.getElementById('fileDragData').value = e.target.result;
  }
  reader.readAsDataURL(file);
}
function getTheFile(e) {
  e.target.style.borderColor='#ccc';
  readFile(e);
}
<input type="file" onchange="readFile(event)">
<input id="fileDragName">
<input id="fileDragSize">
<input id="fileDragType">
<input id="fileDragData">
<div style="width:200px; height:200px; border: 10px dashed #ccc"
     ondragover="this.style.borderColor='#0c0';return false;"       
     ondragleave="this.style.borderColor='#ccc'"       
     ondrop="getTheFile(event); return false;"       
></div>
Magnus
  • 1,584
  • 19
  • 14
1

Awesome work by @BjarkeCK. I made some modifications to his work, to use it as method in jquery:

$.fn.dropZone = function() {
  var buttonId = "clickHere";
  var mouseOverClass = "mouse-over";

  var dropZone = this[0];
  var $dropZone = $(dropZone);
  var ooleft = $dropZone.offset().left;
  var ooright = $dropZone.outerWidth() + ooleft;
  var ootop = $dropZone.offset().top;
  var oobottom = $dropZone.outerHeight() + ootop;
  var inputFile = $dropZone.find("input[type='file']");
  dropZone.addEventListener("dragleave", function() {
    this.classList.remove(mouseOverClass);
  });
  dropZone.addEventListener("dragover", function(e) {
    console.dir(e);
    e.preventDefault();
    e.stopPropagation();
    this.classList.add(mouseOverClass);
    var x = e.pageX;
    var y = e.pageY;

    if (!(x < ooleft || x > ooright || y < ootop || y > oobottom)) {
      inputFile.offset({
        top: y - 15,
        left: x - 100
      });
    } else {
      inputFile.offset({
        top: -400,
        left: -400
      });
    }

  }, true);
  dropZone.addEventListener("drop", function(e) {
    this.classList.remove(mouseOverClass);
  }, true);
}

$('#drop-zone').dropZone();

Working Fiddle

Mr_Green
  • 40,727
  • 45
  • 159
  • 271
1

Just use it.(Html - Css ) ;)

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">    
<style>
    .upload-container {
        position: relative;
    }
    .upload-container input {
        border: 1px solid #92b0b3;
        background: #f1f1f1;
        outline: 2px dashed #92b0b3;
        outline-offset: -10px;
        padding: 100px 0px 100px 250px;
        text-align: center !important;
        width: 500px;
    }
    .upload-container input:hover {
        background: #ddd;
    }   
    .upload-container:before {
        position: absolute;
        bottom: 50px;
        left: 245px;
        content: " (or) Drag and Drop files here. ";
        color: #3f8188;
        font-weight: 900;
    }   
    .upload-btn {
        margin-left: 300px;
        padding: 7px 20px;
    }        
</style>
<script>
             
    function uploadFiles() {
        var files = document.getElementById('file_upload').files;
        if(files.length==0){
            alert("Please first choose or drop any file(s)...");
            return;
        }
        var filenames="";
        for(var i=0;i<files.length;i++){
            filenames+=files[i].name+"\n";
        }
    }
            
</script>
</head>
<body>
    <div class="upload-container">
        <input type="file" id="file_upload" multiple />
    </div>
    <br>
    <button class="upload-btn" onclick="uploadFiles()">Submit</button>  
</body>
</html>
Saeid
  • 422
  • 4
  • 9
-1

What you could do, is display a file-input and overlay it with your transparent drop-area, being careful to use a name like file[1]. {Be sure to have the enctype="multipart/form-data" inside your FORM tag.}

Then have the drop-area handle the extra files by dynamically creating more file inputs for files 2..number_of_files, be sure to use the same base name, populating the value-attribute appropriately.

Lastly (front-end) submit the form.


All that's required to handle this method is to alter your procedure to handle an array of files.

Shark8
  • 4,095
  • 1
  • 17
  • 31
  • 1
    The file input has a `multiple` attribute these days. No need for more than 1 file input. That's not the issue though. How do I get the `File` objects into the file input? I'm thinking this requires some code example... – Rudie Nov 11 '11 at 22:44
  • 1
    @Rudie you can't, that's the problem. – Ricardo Tomasi Nov 14 '11 at 07:17
  • 1
    Can't what? Multiple? Yes, you can. I just said that. The multiple isn't the problem. The getting the files from a (dragged) File object into a file input, that's the problem. – Rudie Nov 15 '11 at 12:54
  • @Rudie getting dragged file(s) into a file input is possible with Chrome/FF (using the `files` property), but i haven't managed in IE - have you had any luck? – jlb Aug 15 '16 at 11:03
  • 1
    @jlb What do you mean "using the files property"? Could you make an answer with relevant code? What I was looking for doesn't work/exist in any browser. – Rudie Aug 15 '16 at 17:09