Drag and Drop - Uploading Multiple Files using Pure JavaScript Tutorial

In this tutorial, you will learn how to create or implement a Drag and Drop File Uploading using Pure JavaScript. This tutorial mainly aims to provide IT/CS Students and new programmers with a reference to handle file uploads on both the client and server sides. Here, the step-by-step tutorial for achieving the main objective is provided with snippets for better understanding. A sample web application source code zip file that demonstrates the tutorial's objective is also provided and is free to download.

What is Drag-and-Drop File Uploading?

Drag-and-Drop File Uploading is a process of handling file uploads on the client side. It allows the end user of a certain system or platform to simply drag the files they desire to upload and drop to a certain container or file drop zone on the platform page.

How to Create a Drag-and-Drop File using JavaScript?

Drag-and-Drop functionality can be achieved using the JavaScript EventListeners. Here are the following event listeners that can be used to achieve the said functionality:

  • ondragover
    • This event listener enables you to create a process, functions, or manipulations that will be triggered when the dragged file hovers over the drop zone field.
  • ondragleave
    • This event listener enables you to create a process, functions, or manipulations that will be triggered when the dragged file leaves the drop zone field.
  • ondrop
    • This event listener enables you to create a process, functions, or manipulations that will be triggered when the dragged file has been dropped at the drop zone field.

Sample Syntax

Here's a sample snippet that demonstrates how to use the said event listeners.

  1.     document.getElementById('drop-zone').ondragover = function(event)
  2.     {
  3.         // Add something here
  4.     }
  5.     document.getElementById('drop-zone').ondragleave = function(event)
  6.     {
  7.         // Add something here
  8.     }
  9.     document.getElementById('drop-zone').ondrop = function(event)
  10.     {
  11.         // Add something here
  12.     }

Example

Here are the source code snippets of simple web applications that demonstrate the Drag-and-Drop Multiple File Upload with a progress bar using the 3 event listeners mentioned above. The application allows the end-users to upload multiple files by simply drag-and-drop the files on the application files drop zone. The uploading process to the server will be executed using the JS HTTP Request and PHP Script.

Interface

Here's the snippet of the application page interface. The file is a combined PHP and HTML script for displaying the file drop zone and uploaded files. I used Bootstrap v5 and Fontawesome Icons for the design of the interface which is loaded using CDNs. Save the file as index.php

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.     <meta charset="UTF-8">
  4.     <meta http-equiv="X-UA-Compatible" content="IE=edge">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>JS Drag and Drop - Upload Multiple File</title>
  7.     <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/css/all.min.css" integrity="sha512-xh6O/CkQoPOWDdYTDqeRdPCVd1SpvCA9XXcUnZS2FmJNp1coAFzvtCN9BmamE+4aHK8yyUHUSCcJHgXloTyT2A==" crossorigin="anonymous" referrerpolicy="no-referrer" />
  8.     <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
  9.     <link rel="stylesheet" href="style.css">
  10.    
  11.     <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.0/js/all.min.js" integrity="sha512-naukR7I+Nk6gp7p5TMA4ycgfxaZBJ7MO5iC3Fp6ySQyKFHOGfpkSZkYVWV5R7u7cfAicxanwYQ5D1e17EfJcMA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  12.     <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3" crossorigin="anonymous"></script>
  13. </head>
  14.     <nav class="navbar navbar-expand-lg navbar-dark bg-primary bg-gradient">
  15.         <div class="container">
  16.             <a class="navbar-brand" href="./">JS Drag and Drop - Upload Multiple File</a>
  17.             <div>
  18.                 <a href="https://sourcecodester.com" class="text-light fw-bolder h6 text-decoration-none" target="_blank">SourceCodester</a>
  19.             </div>
  20.         </div>
  21.     </nav>
  22.     <div class="container-fluid px-5 my-3">
  23.         <div class="col-lg-6 col-md-8 col-sm-12 mx-auto">
  24.             <div class="card rounded-0">
  25.                 <div class="card-body rounded-0">
  26.                     <div class="container-fluid">
  27.                         <div id="msg"></div>
  28.                         <!-- Drag and Drop Field -->
  29.                         <div id="dd-field">
  30.                             <h3 class="text-muted">Drag and Drop Files Here</h3>
  31.                         </div>
  32.                         <div class="my-2">
  33.                             <div class="progress" id="upload-progress-holder" style="display:none">
  34.                                 <div class="progress-bar" id="upload-progress" role="progressbar" aria-label="Example with label" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">0%</div>
  35.                                 </div>
  36.                         </div>
  37.                         <div id="upload-field">
  38.                             <?php
  39.                            if(is_dir("uploads/")):
  40.                            $scandr = scandir("uploads/");
  41.                            foreach($scandr as $file){
  42.                                if(in_array($file, [".", ".."]))
  43.                                continue;
  44.                                $type = mime_content_type("uploads/".$file);
  45.                            ?>
  46.                             <div class="uploaded-file-item">
  47.                                 <?php if(strstr($type, "image/")): ?>
  48.                                     <a href="uploads/<?= $file ?>" class="image-holder" target="_blank">
  49.                                         <img src="uploads/<?= $file ?>" alt="">
  50.                                     </a>
  51.                                 <?php else: ?>
  52.                                     <a href="uploads/<?= $file ?>" class="icon-holder" target="_blank">
  53.                                         <i class="fa-solid fa-file"></i>
  54.                                     </a>
  55.                                 <?php endif; ?>
  56.                                 <div class="text-center"><?= $file ?></div>
  57.                             </div>
  58.                             <?php } ?>
  59.                             <?php endif; ?>
  60.                         </div>
  61.                     </div>
  62.                 </div>
  63.             </div>
  64.         </div>
  65.     </div>
  66.     <script src="upload-file-dd.js"></script>
  67. </body>
  68. </html>

Custom Style

Here is the snippet of the custom cascading stylesheet or CSS for some of the designs of the interface. Save the file style.css.

  1. html, body{
  2.     min-height:100%;
  3.     width:100%;
  4. }
  5. #dd-field{
  6.     width: 100%;
  7.     height: 15vh;
  8.     border: 2px dashed #b5b5b5;
  9.     border-radius: 15px;
  10.     overflow: auto;
  11.     padding: 1em;
  12.     display: flex;
  13.     color: #b5b5b5;
  14.     font-size: 1.5em;
  15.     align-items: center;
  16.     justify-content: center;
  17. }
  18. #upload-field{
  19.     width: 100%;
  20.     height: 45vh;
  21.     border: 2px solid #b5b5b5;
  22.     border-radius: 15px;
  23.     overflow: auto;
  24.     padding: 1em;
  25.     display: flex;
  26.     flex-wrap: wrap;
  27. }
  28. #upload-field:empty{
  29.     align-items: center;
  30.     justify-content: center;
  31. }
  32. #upload-field:empty:after{
  33.     content:"Uploads Directory is empty";
  34.     color: #b5b5b5;
  35.     font-size: 1em;
  36. }
  37. .uploaded-file-item {
  38.     width: 30%;
  39.     margin: 1.5%;
  40. }
  41. .image-holder, .icon-holder {
  42.     width: 100%;
  43.     height: 10vh !important;
  44.     background-color: black;
  45.     border: #b5b5b5;
  46.     border-radius: 5px;
  47.     display: block;
  48. }
  49. .icon-holder{
  50.     color: #fff;
  51.     font-size: 3em;
  52.     text-align: center;
  53. }
  54. .image-holder>img {
  55.     width: 100%;
  56.     height: 100%;
  57.     object-fit: scale-down;
  58.     object-position: center center;
  59. }

PHP API

The following snippet is a PHP script that uploads the files to the server. The script contains a simple logic for managing the files with duplicate filenames. This API will be executed by the JS HTTP Request. Save the file as upload_files.php

  1. <?php
  2. // Upload Directory
  3. $dir = "uploads/";
  4.  
  5. /**
  6.     * Check and Create Uploads Directory If not Existing Yet
  7.     */
  8. if(!is_dir($dir))
  9.     mkdir($dir);
  10.  
  11. if(isset($_FILES['files']) && count($_FILES['files']['tmp_name']) > 0){
  12.     $files = $_FILES['files'];
  13.     $total_files = count($_FILES['files']['tmp_name']);
  14.     $uploaded_files = [];
  15.     $uploaded = 0;
  16.     foreach($files['tmp_name'] as $k => $file){
  17.        
  18.  
  19.         if(!empty($file)){
  20.            
  21.             // Get the File Path Info
  22.             $filepath_part = pathinfo($files['name'][$k]);
  23.             // Get the filename
  24.             $filename = $filepath_part['filename'];
  25.             // Get the extension
  26.             $extension = $filepath_part['extension'];
  27.             // File Full Name w/ Extension
  28.             $filefullname = $filename.".".$extension;
  29.             // Content Mime Type
  30.             $mime_type = mime_content_type($file);
  31.  
  32.             // print($mime_type."<br>");
  33.             // continue;
  34.  
  35.             /**
  36.                 * Check and Rename Filename if file already exists.
  37.                 */
  38.  
  39.             // temporary filename for checking duplicate
  40.             $tmp_name = $filefullname;
  41.  
  42.             //Duplicate Iteration Number
  43.             $i = 0;
  44.             while(true){
  45.                 if($i > 0)
  46.                 $tmp_name = $filename." ($i)".".".$extension;
  47.  
  48.                 if(is_file($dir.$tmp_name)){
  49.                     $i++;
  50.                 }else{
  51.                     $filefullname = $tmp_name;
  52.                     break;
  53.                 }
  54.             }
  55.  
  56.             /**
  57.                 * Move file to uploads directory
  58.                 */
  59.             $upload = move_uploaded_file($file, $dir.$filefullname);
  60.             if($upload){
  61.                 $uploaded_files[] = ["filename" => $filefullname, "type" => $mime_type];
  62.                 $uploaded++;
  63.             }
  64.         }
  65.     }
  66.     if($uploaded == $total_files){
  67.         echo json_encode([
  68.             "status" => 'success',
  69.             "msg" => 'File has been uploaded successfully.',
  70.             "uploads" => $uploaded_files
  71.         ]);
  72.     }elseif($uploaded > 0 && $uploaded < $total_files){
  73.         echo json_encode([
  74.             "status" => 'success',
  75.             "msg" => 'Some Files has been uploaded successfully and some has failed due to some reason.',
  76.             "uploads" => $uploaded_files
  77.         ]);
  78.     }else{
  79.         echo json_encode([
  80.             "status" => 'error',
  81.             "msg" => 'Files has failed due to some reason.'
  82.         ]);
  83.     }
  84. }else{
  85.     echo json_encode([
  86.         "status" => 'error',
  87.         "msg" => 'No files sent on this request.'
  88.     ]);
  89. }

JavaScript

Here is the JavaScript snippet that contains the main object of this tutorial. It has a script that implements the Drag-and-Drop functionality of the system and triggers to upload of the dropped files. Save the file as upload-file-dd.js.

  1. /**
  2. * Check if Upload Field is empty
  3. */
  4. window.onload = function(){
  5.     if(document.getElementById('upload-field').innerText == ""){
  6.         document.getElementById('upload-field').innerHTML = ""
  7.     }
  8. }
  9.  
  10. /**
  11. * Drag and Drop Field Drag Over CSS Change
  12. */
  13. document.getElementById('dd-field').ondragover = function(event)
  14. {
  15.     this.style.borderColor = '#000';
  16.     return false;
  17. }
  18.  
  19. /**
  20. * Drag and Drop Field Drag Leave CSS Change
  21. */
  22. document.getElementById('dd-field').ondragleave = function(event)
  23. {
  24.     this.style.borderColor = '#b5b5b5';
  25.     return false;
  26. }
  27.  
  28.  
  29. /**
  30. * Drag and Drop Field Dropped Files
  31. * Process and Upload Files
  32. */
  33. document.getElementById('dd-field').ondrop = function(event)
  34. {
  35.     event.preventDefault();
  36.     document.getElementById('msg').innerHTML = "";
  37.  
  38.     this.style.borderColor = '#429ebe';
  39.     var form_data  = new FormData();
  40.  
  41.  
  42.     var error = '';
  43.  
  44.     var drop_files = event.dataTransfer.files;
  45.  
  46.     // Allowed Files to Upload
  47.     var valid_files = ['image/jpeg', 'image/png', 'video/mp4', 'application/gzip', 'image/gif', 'text/html', 'application/json', 'application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/msword', 'text/csv', 'text/plain'];
  48.  
  49.     for(var count = 0; count < drop_files.length; count++)
  50.     {
  51.         if(!valid_files.includes(drop_files[count].type))
  52.         {  
  53.             // In File type is not allowed
  54.             error += `<div class="alert alert-danger rounded-0 mb-3"><b>${drop_files[count].name}'s</b> File Type is not valid.</div>`;
  55.        }
  56.        else
  57.        {
  58.            form_data.append("files[]", drop_files[count]);
  59.        }
  60.  
  61.    }
  62.  
  63.    if(error != '')
  64.    {
  65.        // Return Error Message
  66.  
  67.        document.getElementById('msg').innerHTML = error;
  68.        document.getElementById('dd-field').style.borderColor = '#b5b5b5';
  69.    }
  70.    else
  71.    {
  72.        // Display Progress Bar
  73.        document.getElementById('upload-progress-holder').style.display = 'block';
  74.  
  75.  
  76.        /**
  77.        * Upload files
  78.        */
  79.  
  80.        var httpRequest = new XMLHttpRequest();
  81.        httpRequest.open("post", "upload_files.php");
  82.        httpRequest.responseType = "json"
  83.        httpRequest.upload.addEventListener('progress', function(event){
  84.            /**
  85.            * Update Progress Bar while Upload is inProgress
  86.            */
  87.            var percent_completed = Math.round((event.loaded / event.total) * 100);
  88.  
  89.            document.getElementById('upload-progress').style.width = percent_completed + '%';
  90.  
  91.            document.getElementById('upload-progress').innerHTML = percent_completed + '% completed';
  92.  
  93.        });
  94.        httpRequest.addEventListener('load', function(event){
  95.            // Upload Response
  96.            response = httpRequest.response
  97.            // console.log(response)
  98.            if(!!response.status){
  99.                if(response.status == 'success'){
  100.                    // IF File Upload is successfull
  101.                    if(!!response.msg)
  102.                        document.getElementById('msg').innerHTML = `<div class="alert alert-success rounded-0 mb-3">${response.msg}</div>`;
  103.                    if(!!response.uploads){
  104.                        /**
  105.                        * Add Newly Uploaded files to upload field
  106.                        */
  107.                        Object.keys(response.uploads).map(k => {
  108.                            var fname = response.uploads[k].filename
  109.                            var type = response.uploads[k].type
  110.  
  111.                            var el = document.createElement("div")
  112.                            el.classList.add("uploaded-file-item")
  113.                            if(type.includes("image/") === true){
  114.                                el.innerHTML = `
  115.                                    <a href="uploads/${fname}" class="image-holder" target="_blank">
  116.                                        <img src="uploads/${fname}">
  117.                                    </a>
  118.                                    <div class="text-center">${fname}</div>
  119.                                `
  120.                            }else{
  121.                                el.innerHTML = `
  122.                                    <a href="uploads/${fname}" class="icon-holder" target="_blank">
  123.                                        <i class="fa-solid fa-file"></i>
  124.                                    </a>
  125.                                    <div class="text-center">${fname}</div>
  126.                                `
  127.                            }
  128.                            document.getElementById('upload-field').innerHTML = el.outerHTML  + document.getElementById('upload-field').innerHTML
  129.                            document.getElementById('upload-field').scrollTop = 0
  130.                        })
  131.                    }
  132.                }else if(response.status == 'error'){
  133.                    if(!!response.msg)
  134.                        document.getElementById('msg').innerHTML = `<div class="alert alert-danger rounded-0 mb-3">${response.msg}</div>`;
  135.                }else{
  136.                    document.getElementById('msg').innerHTML = `<div class="alert alert-danger rounded-0 mb-3">An error occurred while uploading the files.</div>`;
  137.                }
  138.            }
  139.  
  140.            document.getElementById('dd-field').style.borderColor = '#b5b5b5';
  141.  
  142.        });
  143.  
  144.        httpRequest.send(form_data);
  145.    }
  146. }
  147.  

That's it! You can now test the application source code on your end. The upload directory will be automatically created upon uploading files for the first time using the application. I also provided the application's complete source code zip file with this article and it is free to download. You can download it by clicking the Download Button located below this article.

Snapshots

Main Interface

>Drag-and-Drop Multiple File Upload

Successful File Upload

>Drag-and-Drop Multiple File Upload

There you go! That's the end of this tutorial. I hope this Uploading Drag-and-Drop Multiple Files using JavaScript Tutorial helps you with what you are looking for and will be useful for your current and future projects.

Explore more on this website for more Tutorials and Free Source Codes.

Happy Coding :)

Add new comment