In this tutorial, I will teach you how to upload files with a progress bar using HTML5, CSS3, JavaScript, and PHP. The complete source code of this File Upload with Progress Bar project is given below.
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>File Upload with Progress Bar</title> <link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"/> </head> <body> <div class="wrapper"> <header>File Uploader JavaScript</header> <form action="#"> <input class="file-input" type="file" name="file" hidden> <i class="fas fa-cloud-upload-alt"></i> <p>Browse File to Upload</p> </form> <section class="progress-area"></section> <section class="uploaded-area"></section> </div> <script src="script.js"></script> </body> </html>
script.js
const form = document.querySelector("form"), fileInput = document.querySelector(".file-input"), progressArea = document.querySelector(".progress-area"), uploadedArea = document.querySelector(".uploaded-area"); // form click event form.addEventListener("click", () =>{ fileInput.click(); }); fileInput.onchange = ({target})=>{ let file = target.files[0]; //getting file [0] this means if user has selected multiple files then get first one only if(file){ let fileName = file.name; //getting file name if(fileName.length >= 12){ //if file name length is greater than 12 then split it and add ... let splitName = fileName.split('.'); fileName = splitName[0].substring(0, 13) + "... ." + splitName[1]; } uploadFile(fileName); //calling uploadFile with passing file name as an argument } } // file upload function function uploadFile(name){ let xhr = new XMLHttpRequest(); //creating new xhr object (AJAX) xhr.open("POST", "php/upload.php"); //sending post request to the specified URL xhr.upload.addEventListener("progress", ({loaded, total}) =>{ //file uploading progress event let fileLoaded = Math.floor((loaded / total) * 100); //getting percentage of loaded file size let fileTotal = Math.floor(total / 1000); //gettting total file size in KB from bytes let fileSize; // if file size is less than 1024 then add only KB else convert this KB into MB (fileTotal < 1024) ? fileSize = fileTotal + " KB" : fileSize = (loaded / (1024*1024)).toFixed(2) + " MB"; let progressHTML = `<li class="row"> <i class="fas fa-file-alt"></i> <div class="content"> <div class="details"> <span class="name">${name} • Uploading</span> <span class="percent">${fileLoaded}%</span> </div> <div class="progress-bar"> <div class="progress" style="width: ${fileLoaded}%"></div> </div> </div> </li>`; // uploadedArea.innerHTML = ""; //uncomment this line if you don't want to show upload history uploadedArea.classList.add("onprogress"); progressArea.innerHTML = progressHTML; if(loaded == total){ progressArea.innerHTML = ""; let uploadedHTML = `<li class="row"> <div class="content upload"> <i class="fas fa-file-alt"></i> <div class="details"> <span class="name">${name} • Uploaded</span> <span class="size">${fileSize}</span> </div> </div> <i class="fas fa-check"></i> </li>`; uploadedArea.classList.remove("onprogress"); // uploadedArea.innerHTML = uploadedHTML; //uncomment this line if you don't want to show upload history uploadedArea.insertAdjacentHTML("afterbegin", uploadedHTML); //remove this line if you don't want to show upload history } }); let data = new FormData(form); //FormData is an object to easily send form data xhr.send(data); //sending form data }
style.css
/* Import Google font - Poppins */ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap'); *{ margin: 0; padding: 0; box-sizing: border-box; font-family: "Poppins", sans-serif; } body{ display: flex; align-items: center; justify-content: center; min-height: 100vh; background: #6990F2; } ::selection{ color: #fff; background: #6990F2; } .wrapper{ width: 430px; background: #fff; border-radius: 5px; padding: 30px; box-shadow: 7px 7px 12px rgba(0,0,0,0.05); } .wrapper header{ color: #6990F2; font-size: 27px; font-weight: 600; text-align: center; } .wrapper form{ height: 167px; display: flex; cursor: pointer; margin: 30px 0; align-items: center; justify-content: center; flex-direction: column; border-radius: 5px; border: 2px dashed #6990F2; } form :where(i, p){ color: #6990F2; } form i{ font-size: 50px; } form p{ margin-top: 15px; font-size: 16px; } section .row{ margin-bottom: 10px; background: #E9F0FF; list-style: none; padding: 15px 20px; border-radius: 5px; display: flex; align-items: center; justify-content: space-between; } section .row i{ color: #6990F2; font-size: 30px; } section .details span{ font-size: 14px; } .progress-area .row .content{ width: 100%; margin-left: 15px; } .progress-area .details{ display: flex; align-items: center; margin-bottom: 7px; justify-content: space-between; } .progress-area .content .progress-bar{ height: 6px; width: 100%; margin-bottom: 4px; background: #fff; border-radius: 30px; } .content .progress-bar .progress{ height: 100%; width: 0%; background: #6990F2; border-radius: inherit; } .uploaded-area{ max-height: 232px; overflow-y: scroll; } .uploaded-area.onprogress{ max-height: 150px; } .uploaded-area::-webkit-scrollbar{ width: 0px; } .uploaded-area .row .content{ display: flex; align-items: center; } .uploaded-area .row .details{ display: flex; margin-left: 15px; flex-direction: column; } .uploaded-area .row .details .size{ color: #404040; font-size: 11px; } .uploaded-area i.fa-check{ font-size: 16px; }
php/upload.php
<?php $file_name = $_FILES['file']['name']; //getting file name $tmp_name = $_FILES['file']['tmp_name']; //getting temp_name of file $file_up_name = time().$file_name; //making file name dynamic by adding time before file name move_uploaded_file($tmp_name, "files/".$file_up_name); //moving file to the specified folder with dynamic name ?>
Create a Folder for Uploaded Files
Now you need to create a folder called files
inside the php
folder. Basically, this folder will hold all the uploaded files.