drag drop files into standard html file input
Solution 1
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.
Solution 2
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.
Solution 3
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?
Solution 4
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
Solution 5
//----------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>
Related videos on Youtube
![Rudie](https://i.stack.imgur.com/PYKeq.jpg?s=256&g=1)
Rudie
I'm a web developer that likes cutting edges and doesn't like the backward kind of compatibility.
Updated on July 08, 2022Comments
-
Rudie almost 2 years
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.-
Shark8 over 12 yearsPrepare for some pain if you want to include mac/safari in your compatibilities.
-
Ricardo Tomasi over 12 years@Shark8 actually Safari/Mac is one of the few browsers already supporting this.
-
Rudie over 12 yearsActually, none of the browsers support this. The file input field is read-only (for security) and that's the problem. Stupid security!
-
Ricardo Tomasi over 12 yearsBy this i meant "drag & drop files -- many at a time -- into a standard HTML file input".
-
Lloyd over 12 yearsdrag/drop multiple files to
input type="file" multiple
works fine in Safari -
Matthew Lock about 11 yearsFirefox (20.0.1 on Windows at least) lets you just drag a file into a input file control.
-
Rudie about 11 yearsThe good browsers do, but that's not the issue.
-
-
Rudie over 12 yearsThe 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 theFile
objects into the file input? I'm thinking this requires some code example... -
Ricardo Tomasi over 12 years@Rudie you can't, that's the problem.
-
Rudie over 12 yearsCan'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 over 12 yearsLike 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 =(
-
BjarkeCK over 11 yearsThat's why i added a button aswell^^ But yah your'e right. I wouln't use it eather... Or would i !?
-
Develoger over 10 yearsGood solution yet it does not work on IE < 10 because IE 9 and less does not support HTML5 files API :(
-
Rudie almost 10 yearsWhat does it show the user? Can you make a fiddle or online example?
-
nmz787 about 9 yearsI 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
-
BjarkeCK about 9 years@nmz787 checkout this thread, you might find another solution there. stackoverflow.com/questions/1537223/…
-
Rudie over 8 yearsActually 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.
-
kurdtpage over 8 yearsThis line: document.getElementById('fileDragData').value = files[i].slice(); is not needed, because it is superseded in the reader.onload function
-
jlb almost 8 years@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? -
Rudie almost 8 years@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 almost 8 yearsWaaaaaaaat! 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.
-
jlb almost 8 yearsD'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) andEdge/
(IE12)... -
Tithen-Firion almost 8 years@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. -
John over 7 years@PiotrKowalski I think that would potentially trigger a recursive call until the call stack overflows
-
Tithen-Firion over 7 years@John you are right. My browser handles this well (stops after second
.click()
because file selection window is already open) but you can addclick
listener to file input ande.stopPropagation()
should do the trick. -
Risadinha over 7 yearsFF 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. -
Russell Smith over 7 yearsThis 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.
-
Rudie over 7 yearsYes, 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 =( -
Eddie about 7 yearsI ended up using the style only. Making the input 100% width and height worked better than moving it around.
-
JeFf about 7 yearsFor adding and removing mouse-over class of the drop-zone it would be better to use dragenter and dragleave events.
-
nick about 7 yearsJust 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.
-
jlb about 7 years@nick unfortunately that's not possible with -- sorry :(
-
nick about 7 yearsactually 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 stackoverflow.com/a/43397640/6392779
-
henryC almost 7 yearsLinux / Chrome Version 59.0.3071.115 (Official Build) (64-bit) -- Works! Linux / FF 54.0 -- Does nothing.
-
Dipak almost 7 years@Rudie please click run code snippet and drag-n-drop one image to view, it will show the preview of image dropped.
-
William Entriken over 6 yearsHere is another cute drag and drop application that does NOT involve file uploads. Linking just in case somebody wants to study more. codepen.io/anon/pen/MOPvZK?editors=1010
-
William Entriken over 6 yearsThe IE 10 solution is to degrade and only show the
input type=file
-
Kevin Burke over 6 yearsAm 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? -
LinusGeffarth over 6 yearsI had to apply
evt.preventDefault(); e.stopPropagation()
to all of the following to make this work:drag dragstart dragend dragover dragenter dragleave drop
-
totymedli about 6 yearsThis solution doesn't trigger the
change
event on the input under Firefox, so you have to manually trigger it:fileInput.dispatchEvent(new Event('change'))
. I have FF 58. -
TheRedstoneTaco almost 6 yearsI 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.
-
Fight Fire With Fire almost 6 yearsI 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?
-
Michael almost 6 yearsIt works fine for me in the latest version of Chrome. Make sure you use the right ID's
-
jimiayler over 5 yearsFYI: Fiddle link is broken.
-
Abhishek Singh over 5 yearsIs there a way to get rid of the "no file chosen" which keeps hovering along with our mouse pointer? @BjarkeCK
-
Nikhil VJ about 4 yearshow does one fetch the selected file later on when submitting the form?
-
Wajahath about 3 yearsFor me, this is the coolest solution, No JS. Thanks for adding it here. I never knew the
<input type="file">
support this drag option natively! -
Oleksandr Bratashov about 3 yearsThanks, works! I've created working link jsfiddle.net/abratashov/n42ohkr3/2
-
Fanky almost 3 years@SashaB. no, the fiddle doesn't work in Firefox 91.0.2, Win10. Opens the image instead in the tab.
-
Fanky almost 3 yearsCool, only it seems input is
:valid
even when no file selected (FF) -
Fanky almost 3 yearsOh it works when the input has
required
attribute. But I don't want the input required :) -
Fanky almost 3 yearsFinaly replacing with
.file-area input[type=file]:not([value=""]) + ...
but addingjQuery( 'input[type=file]' ).change( function( e ) { this.defaultValue = this.value;} );
because DOM value attribute doesn't update otherwise. So not pure-css anymore. -
Kameron almost 3 years@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 <input file function.