The standard browser method for uploading files is an <input> tag with type="file". A friendlier method is to allow the user to drag files onto the page from their desktop. Here's how.

The Basics

HTML has long provided an input tag to handle file uploads. It's solid, it's well understood and well supported by server software. It's also a bit ugly, and can sometimes be difficult for users to use if the file selector windo they're presnted with doesn't point to where the files are, and it's not always obvious where files on the desktop are if you're looking for them in the file system.

Enter Drag'n'Drop - just find your files on the desktop and drag them into the web page. Easy and intuitive.

Drag events

Browsers implement a number of drag-related events: drag, dragend, dragenter, dragleave, dragover, dragstart, dragdrop. Some of these are only relevant when handlig drag actions within a page. We'll be concerning ourselves with dragenter, dragleave, dragover and drop.

  • dragenter - fired when a dragged item is dragged into a drop target
  • dragover - fired whenever a dragged item is dragged within a drop target
  • dragleave - fired when a dragged item leaves a drop target
  • drop - fired when an item is dropped on a drop target

Of these, dragenter, dragover and dragleave are used for cosmetic purposes. The really interesting item is drop

Setting up the drop target

Nothing complex here - just some basic HTML and some CSS to make it pretty:
        #dropTarget {
            margin:100px auto;
            border:5px dashed grey;
            border-radius: 20px;
        #dropText {
            font-family: "Segoe UI",Arial,sans-serif;
            margin:0 auto;
        .highlight {

    <div id="dropTarget">
    <p id="dropText">Drop File Here</p>

Add the event handlers

Most elements on a page are not suitable as drop targets. Thus the default actions for dragenter and dragover are to prevent a drop on that element. To allow a drop on an element the event handlers must prevent the default action on those events. This is achieved either by

return false;

or by


The first three event handlers act to provide some visual confirmation that a dragged item is over the target. They do this by adding the highlight class to the target element. For dragenter and dragover we also call preventDefault() to allow the drop on this element.

          dropTarget.addEventListener('dragenter', (e)=>{

        dropTarget.addEventListener('dragover', (e)=>{
        dropTarget.addEventListener('dragleave', (e)=>{

The drop event handler is where the magic happens. The event object contains a list of the dropped files in the detail property. The handler creates a new FormData object and appends the files to it. Finally, the FormData object is posted to the server using fetch.

        dropTarget.addEventListener('drop', (e)=>{
            e.preventDefault(); // Stop the browser doing what it might normally do.
            let formData = new FormData();
            let fileList = e.dataTransfer.files;
            for (let i = 0; i < fileList.length; i++) {
                formData.append('files[]', fileList[i]);
                    body: formData
            ).then((resp)=> {
                if (resp.ok) {
                    alert("Files uploaded successfully");
                } else {
                    alert("Files uploaded successfully");

Handling the upload at the server

Posting the files as part of a FormData object delivers the files to the server exactly as if they'd been selected from an HTML form. The server can use its usual method to unpack the files. In the case of PHP this involves unpacking the $_FILES superglobal array.

Try it!

Drag some files on to the target below. The endpoint should return a list of files and filesizes that are displayed below.

Drop File Here

The download includes a single page demo including all the CHTML, CSS, and Javascript. Also included is a PHP endpoint for your server.

Get the code!

Questions or comments? Contact me!