AJAX File Upload Progress Bar (Pure CSS Javascript)

Welcome to a tutorial on how to create an AJAX file upload with a progress bar. Once upon a time in the Dark Ages of the Internet, we have to use all sorts of third-party libraries to track the upload progress. Those days are gone and we can actually track uploads using only pure Javascript – Read on for an example!

 

 

TABLE OF CONTENTS

 

FILE UPLOAD PROGRESS BAR

All right, let us now get into the steps of building a file upload with a progress bar.

 

UPLOAD PROGRESS BAR DEMO

FILE UPLOAD

0%

* Demo only, will not actually upload.

 

 

PART 1) THE HTML

upload.html
<div id="up-wrap">
  <h2>UPLOAD FILE</h2>

  <!-- (A) PROGRESS BAR -->
  <div id="up-progress">
    <div id="up-bar"></div>
    <div id="up-percent">0%</div>
  </div>
 
  <!-- (B) FILE PICKER -->
  <input type="file" id="up-file" disabled>
  <label for="up-file" id="up-label">
    Select File
  </label>
</div>

That is actually all we need for the HTML, there are only 2 important pieces.

  1. There is a native HTML <progress>, but it cannot be styled with CSS. This is why we are building our own custom progress bar.
    • up-progress is the container of the progress bar.
    • up-bar is the progress bar itself.
    • up-percent the percentage.
  2. Just a “regular Joe” file upload <input type="file"> and the <label>. But take note of how this works – We hide the ugly <input type="file" and make the <label> look like a button.

 

PART 2) JAVASCRIPT INIT PROGRESS BAR

upload.js
var uprog = {
  // (A) INIT
  hBar : null, // html progress bar
  hPercent : null, // html upload percentage
  hFile : null, // html file picker
  init : () => {
    // (A1) GET HTML ELEMENTS
    uprog.hBar = document.getElementById("up-bar");
    uprog.hPercent = document.getElementById("up-percent");
    uprog.hFile = document.getElementById("up-file");
 
    // (A2) ATTACH AJAX UPLOAD + ENABLE UPLOAD
    uprog.hFile.onchange = uprog.upload;
    uprog.hFile.disabled = false;
  },
}
window.addEventListener("load", uprog.init);

On window load, uprog.init() will run. No need to panic, all it does is to grab the necessary HTML elements and enable the upload button.

 

 

PART 3) JAVASCRIPT AJAX UPLOADER

upload.js
// (B) HELPER - UPDATE PROGRESS BAR
update : percent => {
  percent = percent + "%";
  uprog.hBar.style.width = percent;
  uprog.hPercent.innerHTML = percent;
  if (percent == "100%") { uprog.hFile.disabled = false; }
},
 
// (C) PROCESS UPLOAD
upload : () => {
  // (C1) GET FILE + UPDATE HTML INTERFACE
  let file = uprog.hFile.files[0];
  uprog.hFile.disabled = true; // disable upload button
  uprog.hFile.value = ""; // reset file picker
 
  // (C2) AJAX UPLOAD
  let xhr = new XMLHttpRequest(),
      data = new FormData();
  data.append("upfile", file);
  xhr.open("POST", "upload.php");
 
  // (C3) UPLOAD PROGRESS
  let percent = 0, width = 0;
  xhr.upload.onloadstart = evt => uprog.update(0);
  xhr.upload.onloadend = evt => uprog.update(100);
  xhr.upload.onprogress = evt => {
    percent = Math.ceil((evt.loaded / evt.total) * 100);
    uprog.update(percent);
  };
 
  // (C4) ON LOAD & ERRORS
  xhr.onload = function () {
    if (this.response!= "OK" || this.status!=200) {
      // @TODO - DO SOMETHING ON ERROR
      // alert("ERROR!");
      // reset form?
      console.log(this);
      console.log(this.response);
      console.log(this.status);
    } else {
      uprog.update(100);
      // @TODO - DO SOMETHING ON COMPLETE
    }
  };
  xhr.onerror = err => console.error(err);
 
  // (C5) GO!
  xhr.send(data);
}

Don’t be intimidated by the seemingly “difficult” Javascript here. Not going to explain line-by-line, but the essential sections are:

  • (B) uprog.update() Just a helper function to update the HTML progress bar.
  • (C) uprog.upload() Runs when the user selects a file. Trace through section-by-section, and you will do alright.
    • (C1) Get the selected file to upload.
    • (C2) Create a new XMLHttpRequest() object to handle the AJAX upload.
    • (C3) Update the HTML when the upload progresses.
    • (C4) This is for you to complete – What to when the upload completes, or when an error occurs.

 

 

PART 4) SERVER-SIDE UPLOAD HANDLER

upload.php
<?php
// (A) MOVE UPLOADED FILE
$source = $_FILES["upfile"]["tmp_name"];
$destination = $_FILES["upfile"]["name"];
move_uploaded_file($source, $destination);

// (B) RESPONSE
echo "OK";

This one is in PHP, but just handle the upload “as usual” in whatever language you are using. The echo "OK" response will be picked up in xhr.onload of the Javascript – Use this to serve a notification.

 

DOWNLOAD & NOTES

Here is the download link to the example code, so you don’t have to copy-paste everything.

 

SORRY FOR THE ADS...

But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.

Buy Me A Coffee Code Boxx eBooks

 

EXAMPLE CODE DOWNLOAD

Click here for the source code on GitHub gist, just click on “download zip” or do a git clone. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

EXTRA BITS & LINKS

We have now finished with all the demo scripts, and here are a couple of extras that you may find useful.

 

UPLOAD LIMIT

If you are using PHP as the server-side script, take note that there is a file size limit. While we can quite easily raise the upload limits, a resumable upload simply makes more sense for large files. Check out my other guide on “ways to upload large files in PHP”, links right below.

 

 

FILE TYPE RESTRICTION

Just add an accept="FILE TYPES" to <input type="file">. For example:

  • <input type="file" accept="image/*">
  • <input type="file" accept="video/*">
  • <input type="file" accept="audio/*">
  • <input type="file" accept=".doc,.docx">

But it is still safer to set these restrictions and checks on the server side.

 

LINKS & REFERENCES

 

THE END

Thank you for reading, and we have come to the end of this guide. I hope it has helped you with your project, and if you have anything to add to the guide, please feel free to comment below. Good luck and happy coding!

6 thoughts on “AJAX File Upload Progress Bar (Pure CSS Javascript)”

  1. Nice tutorial. Do you have an idea to create file downloader with progress bar just like Mega.nz?

  2. Hi!!

    Nice tutorial but if you get an error, e.g select a rar-file (validation error) you receive an error message but the progress bar still moves to 100% after the error message.

    Is it possible to display how meny procent that has been uploaded?

    1. Not quite sure if your file type check is on the server or client-side. Either way –

      1) If you want to reset to zero on upload error, add xhr.upload.onerror = function (evt) { bar.style.width = 0; };
      2) The upload percentage is calculated in xhr.upload.onprogress = function (evt) { percent = evt.loaded / evt.total; }
      3) The “accuracy” totally depends on how often the browser returns loaded and total.

Comments are closed.