Creating a multiple file uploader with a progress bar is an excellent project for beginner web developers. It combines basic web development concepts with practical features, offering a hands-on learning experience that is both rewarding and educational.
In this blog post, I will guide you through creating a file uploader using HTML, CSS, and JavaScript that allows users to upload multiple files by either clicking a browse button or dragging and dropping them. A progress bar and file size will update dynamically to display the uploading status.
Additionally, users will have the option to cancel the file-uploading process by clicking a cancel button. There will also be text updating users about the current file status, such as uploading, canceled, or uploaded.
Since vanilla JavaScript alone cannot handle file uploads to a server, a few lines of PHP code will be utilized to receive and store the files on the server.
Why should beginners create this project?
By creating this file-uploading project, beginners can gain the following skills:
- HTML Basics: You’ll gain a solid understanding of form elements and file input controls.
- CSS Styling: Learn how to style forms and progress bars to create visually appealing interfaces.
- JavaScript Fundamentals: Discover how to manipulate DOM elements, handle events, and work with file objects.
- PHP Integration: Get a taste of server-side scripting, an essential aspect of web development.
- Real-World Skills: File uploading is a common feature in web applications. Mastering it prepares you for more complex projects.
Video Tutorial of File Uploading in HTML CSS & JavaScript
The YouTube video above is a great resource if you prefer learning from video tutorials. In this video, I explain each line of code and provide informative comments to make the process of creating your file uploader easy to follow, especially for beginners.
However, if you prefer reading blog posts or need a step-by-step guide for this project, you can keep reading this post.
Steps to Create File Uploader in HTML CSS & JavaScript
To implement this project, we will be using PHP, so you’ll need to set up a local server environment. Download and install XAMPP to run PHP files on your local machine. Once XAMPP is installed, follow these step-by-step instructions:
- First, create a folder with any name you like, e.g.,
file-uploader
. Then, create the necessary files inside it. - Create a file named
index.html
. This will serve as the main HTML file for your project.
Create a file namedstyle.css
. This file will contain all the CSS code for styling your file uploader. - Create a file named
script.js
. This file will include the JavaScript code to handle file uploads and user interactions. - Create a file named
api.php
. This file will contain the PHP code necessary to process and store uploaded files. - Create a folder named
uploads
. This directory will store all the files uploaded via the file uploader.
Once you have finished creating the necessary files and folders for this project, paste the given code into the specified file.
To start, add the following HTML codes to your index.html
file. These codes include all essential HTML elements, such as div, ul, input, and more for the project.
<!DOCTYPE html> <!-- Coding By CodingNepal - www.codingnepalweb.com --> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>File Uploader JavaScript | CodingNepal</title> <link rel="stylesheet" href="style.css"> <!-- Linking Box Icon for Icons --> <link rel="stylesheet" href="https://unpkg.com/[email protected]/css/boxicons.min.css"> <script src="script.js" defer></script> </head> <body> <div class="file-uploader"> <div class="uploader-header"> <h2 class="uploader-title">File Uploader</h2> <h4 class="file-completed-status"></h4> </div> <ul class="file-list"></ul> <div class="file-upload-box"> <h2 class="box-title"> <span class="file-instruction">Drag files here or</span> <span class="file-browse-button">browse</span> </h2> <input class="file-browse-input" type="file" multiple hidden> </div> </div> </body> </html>
Next, add the following CSS codes to your style.css
file to apply visual styling to your file uploader.
/* Importing Inter Font from Google Fonts */ @import url('https://fonts.googleapis.com/css2?family=Inter:[email protected]&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Inter", sans-serif; } body { display: flex; align-items: center; padding: 15px; justify-content: center; min-height: 100vh; background: #5145BA; } .file-uploader { width: 500px; background: #fff; border-radius: 5px; box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); } .file-uploader .uploader-header { display: flex; padding: 20px; background: #EEF1FB; align-items: center; border-radius: 5px 5px 0 0; justify-content: space-between; } .uploader-header .uploader-title { font-size: 1.2rem; font-weight: 700; text-transform: uppercase; } .uploader-header .file-completed-status { font-size: 1rem; font-weight: 500; color: #333; } .file-uploader .file-list { list-style: none; width: 100%; padding-bottom: 10px; max-height: 400px; overflow-y: auto; scrollbar-color: #999 transparent; scrollbar-width: thin; } .file-uploader .file-list:has(li) { padding: 20px; } .file-list .file-item { display: flex; gap: 14px; margin-bottom: 22px; } .file-list .file-item:last-child { margin-bottom: 0px; } .file-list .file-item .file-extension { height: 50px; width: 50px; color: #fff; display: flex; text-transform: uppercase; align-items: center; justify-content: center; border-radius: 15px; background: #5145BA; } .file-list .file-item .file-content-wrapper { flex: 1; } .file-list .file-item .file-content { display: flex; width: 100%; justify-content: space-between; } .file-list .file-item .file-name { font-size: 1rem; font-weight: 600; } .file-list .file-item .file-info { display: flex; gap: 5px; } .file-list .file-item .file-info small { color: #5c5c5c; margin-top: 5px; display: block; font-size: 0.9rem; font-weight: 500; } .file-list .file-item .file-info .file-status { color: #5145BA; } .file-list .file-item .cancel-button { align-self: center; border: none; outline: none; background: none; cursor: pointer; font-size: 1.4rem; } .file-list .file-item .cancel-button:hover { color: #E3413F; } .file-list .file-item .file-progress-bar { width: 100%; height: 3px; margin-top: 10px; border-radius: 30px; background: #d9d9d9; } .file-list .file-item .file-progress-bar .file-progress { width: 0%; height: inherit; border-radius: inherit; background: #5145BA; } .file-uploader .file-upload-box { margin: 10px 20px 20px; border-radius: 5px; min-height: 100px; display: flex; align-items: center; justify-content: center; border: 2px dashed #B1ADD4; transition: all 0.2s ease; } .file-uploader .file-upload-box.active { border: 2px solid #5145BA; background: #F3F6FF; } .file-uploader .file-upload-box .box-title { font-size: 1.05rem; font-weight: 500; color: #626161; } .file-uploader .file-upload-box.active .box-title { pointer-events: none; } .file-upload-box .box-title .file-browse-button { color: #5145BA; cursor: pointer; } .file-upload-box .box-title .file-browse-button:hover { text-decoration: underline; }
Add the following JavaScript code to your script.js
file. This script manages file uploads, and user interactions, updates the DOM, and provides other functionalities for the file uploader.
const fileList = document.querySelector(".file-list"); const fileBrowseButton = document.querySelector(".file-browse-button"); const fileBrowseInput = document.querySelector(".file-browse-input"); const fileUploadBox = document.querySelector(".file-upload-box"); const fileCompletedStatus = document.querySelector(".file-completed-status"); let totalFiles = 0; let completedFiles = 0; // Function to create HTML for each file item const createFileItemHTML = (file, uniqueIdentifier) => { // Extracting file name, size, and extension const {name, size} = file; const extension = name.split(".").pop(); const formattedFileSize = size >= 1024 * 1024 ? `${(size / (1024 * 1024)).toFixed(2)} MB` : `${(size / 1024).toFixed(2)} KB`; // Generating HTML for file item return `<li class="file-item" id="file-item-${uniqueIdentifier}"> <div class="file-extension">${extension}</div> <div class="file-content-wrapper"> <div class="file-content"> <div class="file-details"> <h5 class="file-name">${name}</h5> <div class="file-info"> <small class="file-size">0 MB / ${formattedFileSize}</small> <small class="file-divider">•</small> <small class="file-status">Uploading...</small> </div> </div> <button class="cancel-button"> <i class="bx bx-x"></i> </button> </div> <div class="file-progress-bar"> <div class="file-progress"></div> </div> </div> </li>`; } // Function to handle file uploading const handleFileUploading = (file, uniqueIdentifier) => { const xhr = new XMLHttpRequest(); const formData = new FormData(); formData.append("file", file); // Adding progress event listener to the ajax request xhr.upload.addEventListener("progress", (e) => { // Updating progress bar and file size element const fileProgress = document.querySelector(`#file-item-${uniqueIdentifier} .file-progress`); const fileSize = document.querySelector(`#file-item-${uniqueIdentifier} .file-size`); // Formatting the uploading or total file size into KB or MB accordingly const formattedFileSize = file.size >= 1024 * 1024 ? `${(e.loaded / (1024 * 1024)).toFixed(2)} MB / ${(e.total / (1024 * 1024)).toFixed(2)} MB` : `${(e.loaded / 1024).toFixed(2)} KB / ${(e.total / 1024).toFixed(2)} KB`; const progress = Math.round((e.loaded / e.total) * 100); fileProgress.style.width = `${progress}%`; fileSize.innerText = formattedFileSize; }); // Opening connection to the server API endpoint "api.php" and sending the form data xhr.open("POST", "api.php", true); xhr.send(formData); return xhr; } // Function to handle selected files const handleSelectedFiles = ([...files]) => { if(files.length === 0) return; // Check if no files are selected totalFiles += files.length; files.forEach((file, index) => { const uniqueIdentifier = Date.now() + index; const fileItemHTML = createFileItemHTML(file, uniqueIdentifier); // Inserting each file item into file list fileList.insertAdjacentHTML("afterbegin", fileItemHTML); const currentFileItem = document.querySelector(`#file-item-${uniqueIdentifier}`); const cancelFileUploadButton = currentFileItem.querySelector(".cancel-button"); const xhr = handleFileUploading(file, uniqueIdentifier); // Update file status text and change color of it const updateFileStatus = (status, color) => { currentFileItem.querySelector(".file-status").innerText = status; currentFileItem.querySelector(".file-status").style.color = color; } xhr.addEventListener("readystatechange", () => { // Handling completion of file upload if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { completedFiles++; cancelFileUploadButton.remove(); updateFileStatus("Completed", "#00B125"); fileCompletedStatus.innerText = `${completedFiles} / ${totalFiles} files completed`; } }); // Handling cancellation of file upload cancelFileUploadButton.addEventListener("click", () => { xhr.abort(); // Cancel file upload updateFileStatus("Cancelled", "#E3413F"); cancelFileUploadButton.remove(); }); // Show Alert if there is any error occured during file uploading xhr.addEventListener("error", () => { updateFileStatus("Error", "#E3413F"); alert("An error occurred during the file upload!"); }); }); fileCompletedStatus.innerText = `${completedFiles} / ${totalFiles} files completed`; } // Function to handle file drop event fileUploadBox.addEventListener("drop", (e) => { e.preventDefault(); handleSelectedFiles(e.dataTransfer.files); fileUploadBox.classList.remove("active"); fileUploadBox.querySelector(".file-instruction").innerText = "Drag files here or"; }); // Function to handle file dragover event fileUploadBox.addEventListener("dragover", (e) => { e.preventDefault(); fileUploadBox.classList.add("active"); fileUploadBox.querySelector(".file-instruction").innerText = "Release to upload or"; }); // Function to handle file dragleave event fileUploadBox.addEventListener("dragleave", (e) => { e.preventDefault(); fileUploadBox.classList.remove("active"); fileUploadBox.querySelector(".file-instruction").innerText = "Drag files here or"; }); fileBrowseInput.addEventListener("change", (e) => handleSelectedFiles(e.target.files)); fileBrowseButton.addEventListener("click", () => fileBrowseInput.click());
Finally, add the following PHP code to your api.php
file. This script is used to receive the user-selected file and save it to a specified folder with a dynamic file name.
<?php // Specify the folder where files will be uploaded $folder = "uploads/"; // Move the uploaded file to the specified folder // $_FILES['file']['tmp_name'] is the temporary file name // $_FILES['file']['name'] is the original file name move_uploaded_file($_FILES['file']['tmp_name'], $folder . time() . '_' . $_FILES['file']['name']);
Once you have added all the necessary code to your files, you need to move your project folder into the htdocs folder within your XAMPP installation directory. This step is crucial because the htdocs folder is the default directory where XAMPP looks for files to serve via the local server. Typically, the htdocs folder path can be c:/xampp/htdocs
.
Now you’re ready to use your file uploader. To get started, open the XAMPP Control Panel and start the Apache server. Next, open your browser and enter the URL: localhost/your-project-folder-name
. For example, if your project folder is named “file-uploader,” you would go to localhost/file-uploader
.
You can now test your file uploader by uploading files through the interface. Enjoy the functionality and features you’ve implemented, including the dynamic progress bar, file size display, and the ability to cancel uploads.
Conclusion and Final words
By completing this project, you’ve learned how to create a functional multiple-file uploader with a progress bar using HTML, CSS, and JavaScript. You also learned how to handle file uploads on the server using PHP.
This project not only reinforces your understanding of web development basics but also equips you with a practical skill that is highly relevant in many web applications.
To take this file uploader project a step further, consider adding features such as file type validation (png, jpg, mp4), size limits (< MB), and improved error handling.
Happy Coding!
In the picture you shown the delete button, but in this project its unavailable.
Wow!
Thanks for Coding Nepal I have able to create more beautiful site by using your templates
Glad to hear that. Keep going and happy coding!
how can we delete any files if its uploaded by mistake??
please help.
wow.. amazing video i loved your videos
Please can you help me create a short video sharing website like tiktok