HTML/PHP: Drag and drop upload files


Note: this article shows how you can create a drag-and-drop upload field to upload multiple files with some basic HTML, CSS and JavaScript.
Using Contact Form 7? Check out this article instead: How to upload multiple files with drag and drop with Contact Form 7.


In most modern browsers, you can drag files to the upload button by default. No extra code needed.

Code:

<form>
  <input type="file" name="my-file" multiple>
</form>

Give it a try yourself. Just drag some files to Choose files button:

But a lot of end users probably don’t know this and it doesn’t look too appealing, so it might be a good idea to replace the upload button with a clear drop-area, like this:

This still is a bit of a pain but not quite as bad as it used to be, because these days all modern browsers, including Firefox, allow us to set the uploaded files in a file input via javascript.

<unimportant-side-note> This article assumes you are using a modern up-to-date browser. If you are interested in supporting legacy browsers and older versions, check out this article on CSS-tricks. I don’t care much for people still using outdated browsers. Because I’m lazy. But also because I think more developers shouldn’t care about it. If fewer and fewer developers care about old browsers, less and less people will keep using them. In my opinion it’s the most efficient way that we developers can help push the web forward. </unimportant-side-note>

Live example

See live example here: https://conditional-fields-cf7.bdwm.be/wp-content/themes/wpcf7cf_theme2/draganddropupload.php

Don’t worry, we are not processing any of the files you upload here.

The code

Want to create this page yourself? Create a PHP file and paste this code inside:

<?php
    $uploaded_filenames = '';
    if ($_FILES['files']['name'] && $_FILES['files']['name'][0]) {
        // TODO: Process uploaded files.
        // Easy to do yourself with a little help from Google: https://www.google.com/search?q=php+upload+multiple+files+with+single+file+input
        $uploaded_filenames = 'You just uploaded these files: <ul><li>'.implode('</li><li>', $_FILES['files']['name']).'</li></ul>';
    }
?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
<style>
    .box {
        background-color: white;
        outline: 2px dashed black;
        height: 400px;
    }
    .box.is-dragover {
        background-color: grey;
    }

    .box {
        display:flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
    }

    .box label strong {
        text-decoration: underline;
        color: blue;
        cursor: pointer;
    }

    .box label strong:hover {
        color: blueviolet
    }

    .box input {
        display: none;
    }
</style>
</head>
<body>
    <?php echo $uploaded_filenames; ?>
    <form method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>" enctype="multipart/form-data">
        <div class="box">
            <label>
                <strong>Choose files</strong>
                <span>or drag them here.</span>
                <input class="box__file" type="file" name="files[]" multiple />
            </label>
            <div class="file-list"></div>
        </div>
        <button>Submit</button>
    </form>

    <script>

        const box = document.querySelector('.box');
        const fileInput = document.querySelector('[name="files[]"');
        const selectButton = document.querySelector('label strong');
        const fileList = document.querySelector('.file-list');

        let droppedFiles = [];

        [ 'drag', 'dragstart', 'dragend', 'dragover', 'dragenter', 'dragleave', 'drop' ].forEach( event => box.addEventListener(event, function(e) {
            e.preventDefault();
            e.stopPropagation();
        }), false );

        [ 'dragover', 'dragenter' ].forEach( event => box.addEventListener(event, function(e) {
            box.classList.add('is-dragover');
        }), false );

        [ 'dragleave', 'dragend', 'drop' ].forEach( event => box.addEventListener(event, function(e) {
            box.classList.remove('is-dragover');
        }), false );

        box.addEventListener('drop', function(e) {
            droppedFiles = e.dataTransfer.files;
            fileInput.files = droppedFiles;
            updateFileList();
        }, false );

        fileInput.addEventListener( 'change', updateFileList );

        function updateFileList() {
            const filesArray = Array.from(fileInput.files);
            if (filesArray.length > 1) {
                fileList.innerHTML = '<p>Selected files:</p><ul><li>' + filesArray.map(f => f.name).join('</li><li>') + '</li></ul>';
            } else if (filesArray.length == 1) {
                fileList.innerHTML = `<p>Selected file: ${filesArray[0].name}</p>`;
            } else {
                fileList.innerHTML = '';
            }
        }

    </script>
</body>
</html>