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!

ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.

 

TABLE OF CONTENTS

Download & Demo Upload Progress Useful Bits & Links
The End

 

 

DOWNLOAD & DEMO

Firstly, here is the download link to the example code as promised.

 

QUICK NOTES

  • Open upload.html for the demo. Take note that the server-side is PHP, you need to create your own upload handler if using other languages.
  • Captain Obvious to the rescue, AJAX upload will only work with http://, not file://.
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.

 

EXAMPLE CODE DOWNLOAD

Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.

 

UPLOAD PROGRESS BAR DEMO

FILE UPLOAD

0%

* Demo only, will not actually upload.

 

 

FILE UPLOAD PROGRESS BAR

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

 

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 = () => { DO SOMETHING };
 
  // (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.

 

USEFUL 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. 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.

Leave a Comment

Your email address will not be published.