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
* Demo only, will not actually upload.
PART 1) THE 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.
- 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.
- 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
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
// (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
<?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
- Simple Drag-and-Drop File Upload – Code Boxx
- 3 Ways to Upload Large Files in PHP – Code Boxx
- Javascript File API – MDN
- XMLHttpRequest.upload – MDN
- HTML accept attribute – MDN
- Example on CodePen – File Upload Progress Bar
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!
Works great for small files but large file do not appear in the directory
As above. https://code-boxx.com/upload-large-files-php/
Or do a “how to handle large file upload” in whatever server-side language you are using.
Nice tutorial. Do you have an idea to create file downloader with progress bar just like Mega.nz?
Of course, I know how it works. BUT –
https://code-boxx.com/faq/#help “Requests for new features and tutorials may be considered, but will not be immediately answered.”
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?
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.