In this article, we will take a deep dive into file handling in JavaScript; starting by exploring how files work, how to access them, how to upload them to a server, and some third-party services you can use while managing files for your applications. Let's dive in and discover the world of file handling in JavaScript on the web! How Do Files Work in the Browser? Before understanding how files are represented on the web, we must understand the in JavaScript. Blob Blob According to , a Blob object represents a file-like object of immutable raw data that can be read as text or binary data and converted into a , which further allows its methods to process the data as needed. MDN Web Docs ReadableStream A simple example of a blob would be creating it via the constructor: Blob const array = ['<span>hello</span>','<span>world</span>']; const blob = new Blob(array, { type: "text/html" }); Here, the constructor accepts an object such as an , strings, etc., or a mix of any of such elements as the first argument and returns a blob whose content is the concatenation of the values in the array. Blob iterable Array ArrayBuffer The second argument is an options object with an optional type property for specifying the of the blob. MIME type If you try running the above snippet in your browser console and then try logging the output of the variable, you'll see an output like this: blob > blob Blob {size: 36, type: 'text/html'} You can also do to get the blob size in bytes, which will be 36 in the above case. blob.size Blob also has some instance methods, which allow us to read the data from the Blob or create a new Blob with the subset of the data of the original Blob. For instance, the method returns a that resolves with a string containing the contents of the blob interpreted as UTF-8. text Promise blob.text().then(data => { console.log(data); // <span>hello</span><span>world</span> }); File The enables JavaScript on a webpage to provide information about files and access their content. The File object is a specific type of Blob, meaning it inherits all the properties and methods of Blob. File interface Like the constructor, the constructor also accepts iterable objects , , etc., and other Blobs as its first argument. The second argument is the file's name or the path to the file. Blob File Array ArrayBuffer const array = ['<span>hello</span>','<span>world</span>']; const file = new File(array, "index.html", { type: "text/html" }); In the options object, the constructor also accepts a property called , which, as the name suggests, is a read-only property that stores the last modified date of the file and defaults to . File lastModifiedAt Date.now() Now similar to Blob, you can perform all the actions for reading the file's content. You can also download the file by creating an object URL for the file via the method, which creates a string containing a URL representing a File, Blob, or MediaSource object. URL.createObjectURL So we can download the above file with the following snippet: const array = ['<span>hello</span>','<span>world</span>']; const file = new File(array, "index.html", { type: "text/html" }); // Create a download URL for the File object const downloadUrl = URL.createObjectURL(file); // Create an anchor element for the download link var downloadLink = document.createElement('a'); // Set the download link's href attribute to the download URL downloadLink.href = downloadUrl; // Set the download link's download attribute to the filename of the File object downloadLink.download = file.name; // Programmatically click the download link to initiate the file download downloadLink.click(); // Revoke (cleanup) the download URL to free up memory URL.revokeObjectURL(downloadUrl); You can try running the above script in the browser console, and you'll see a file called with the content getting downloaded. index.html <span>hello</span><span>world</span> Accessing Files On the Web Now that we understand how the File interface works, let's look into how you can access files in your web applications. Using the , you can ask the user to select local files and then read the content of those files, usually using the element. The file input in JavaScript returns a via the property. This object lets you access the files selected by the user. File API <input type= "file"> FileList files To understand how this API works, let's look at a quick example inspired by the , where we ask for image input from the user and display them with their sizes in KB. MDN docs <!DOCTYPE html> <html> <head> <title>File handling demo</title> <meta charset="UTF-8" /> </head> <body> <input type="file" id="fileElem" multiple accept="image/*" /> <div id="fileList"> <p>No files selected!</p> </div> <script> const fileElem = document.getElementById("fileElem"); const fileList = document.getElementById("fileList"); fileElem.addEventListener( "change", () => { if (!fileElem.files.length) { fileList.innerHTML = "<p>No files selected!</p>"; } else { fileList.innerHTML = ""; const list = document.createElement("ul"); fileList.appendChild(list); for (let i = 0; i < fileElem.files.length; i++) { const li = document.createElement("li"); list.appendChild(li); const img = document.createElement("img"); img.src = URL.createObjectURL(fileElem.files[i]); img.height = 60; img.onload = () => { URL.revokeObjectURL(img.src); }; li.appendChild(img); const info = document.createElement("span"); info.innerHTML = `${fileElem.files[i].name}: ${Math.round( fileElem.files[i].size / 1024 )} KB`; li.appendChild(info); } } }, false ); </script> </body> </html> Check out the live . demo on CodeSandbox What's happening in the above snippet is: We have a file input element that only accepts images via the attribute with the id and a with the id , which initially contains a paragraph saying, “No files selected” accept fileElem div fileList Then in JavaScript, we get the DOM elements for both the file input and the div and attach a listener to the file input element. change Now whenever the user selects a single file or multiple files, the change event is triggered, which does the following stuff: It checks whether the user has selected any files by checking the length property of the FileList object we get via . If it doesn't have any files, we just set the HTML of the div to the same initial value again. fileElem.files fileList If it has files, we create an unordered list ( ) element, add it to the div, and then iterate over the files creating and appending a element for each file. ul fileList li Within each tag, we create an element that will be added to the tag. Then create an object URL for the file via the method we saw in the last section and set the img src to it. We also revoke the object URL via once the image is loaded to free up the memory. li img li URL.createObjectURL URL.revokeObjectURL Lastly, we also create another span in which we calculate the image size in KiloBytes by getting the size of the file via the property and dividing it by 1024. size Uploading Files to a Remote Server In the previous section, we learned how to use the Files API to accept files from the user and perform some operations in the browser, such as displaying the file size and preview for images. However, in most real-world scenarios, the primary goal of accepting files is to upload them to a remote server for storage or further processing. Let's take a simple example of how we can upload a file to a server with the progress being shown to the user as the file gets uploaded. The server then stores the file in its local file system and returns the file's name and size as the response. This is what the code for the frontend would look like: <!DOCTYPE html> <html> <head> <title>File Upload Example</title> </head> <body> <h1>File Upload Example</h1> <form id="uploadForm"> <input type="file" name="file" id="fileInput"> <button type="submit">Upload</button> </form> <progress id="progressBar" value="0" max="100"></progress> <div id="status"></div> <script> document.getElementById('uploadForm').addEventListener('submit', (event) => { event.preventDefault(); const fileInput = document.getElementById('fileInput'); const file = fileInput.files[0]; if (!file) { alert('Please select a file to upload'); return; } const progressBar = document.getElementById('progressBar'); progressBar.value = 0; // Reset progress bar const statusContainer = document.getElementById('status'); statusContainer.textContent = ''; // Clear status container const xhr = new XMLHttpRequest(); xhr.open('POST', '/upload'); xhr.upload.addEventListener('progress', (event) => { if (event.lengthComputable) { const progress = Math.round((event.loaded / event.total) * 100); // Calculate upload progress progressBar.value = progress; // Update progress bar } }); xhr.onreadystatechange = () => { if (xhr.readyState === XMLHttpRequest.DONE) { if (xhr.status === 200) { const message = xhr.responseText; statusContainer.textContent = message; // Update status container } else { const error = xhr.responseText || 'Failed to upload file'; alert(`Error: ${error}`); } } }; const formData = new FormData(); formData.append('file', file); xhr.send(formData); }); </script> </body> </html> Check out the . demo with the complete code for the server on CodeSandbox In this example, when the user uploads a file, they will see progress as the file gets uploaded, and they will see the file's name and the file's size, which would be returned from the server. A brief overview of what's happening in the above snippet is as follows: We create a simple form with file input and an upload button to submit the form. We also have a progress bar in the HTML which will be updated when the file is uploaded. Then in the JavaScript code, we attach an event listener to the form for the submit action in which we first get the selected file and initialize the progress bar to its initial state. After that, we create an object which will be used to make an HTTP request to upload the file to our server. For the object we: XHR xhr We initialize a new post request to the endpoint via the method. /upload open We then add the to the object and update the progress bar in the listener based on progress event listener xhr event.loaded We also add another event listener for in which, once the request is finished, we check for 200 status and update the div with the value returned from the server. onreadystatechange status Lastly, we create a new object which provides a way to construct a set of key/value pairs representing form fields and their values. FormData It uses the same format a form would use if the encoding type were set to ; this type also allows up to upload file data. "multipart/form-data" We then add the file added by the user to the key in the object, and then send the request with the via method on the object. file formData formData send xhr On the server, we use the package to save the file uploaded by the user to the file system and return the file name and size. The server code is out of the scope of this article, but if you're curious, you can check it out in the in the file. multer same sandbox linked above app.js Using Third-Party Services for Managing File Uploads As we saw in the last section, uploading files to a remote server is more complicated than making regular API requests to the server, and that was just for the frontend. A lot more goes into building a robust file upload system from scratch, which can be time-consuming and costly, involving server infrastructure, storage, bandwidth, security measures, handling all the edge cases, and ensuring scalability and reliability. This is why it is recommended to use cloud-based file storage services like , which offers an API for developers to integrate file upload and storage capabilities into their applications. Amazon S3 You can also use a full-fledged solution with or , which, apart from providing a managed file storage infrastructure, also provides you with many other features like interactive file upload widgets that allows your users to upload files from a variety of sources, provide to ensure fast and reliable global access to your assets, perform transformations on assets like images giving the browser the ability to decide what kind of images to request based on viewport information and user-defined breakpoints, and many more features. Filestack Cloudinary CDN Let's take a quick look at an example of how you can integrate the widget into your application: Filestack File Picker <!DOCTYPE html> <html> <head> <title>File Upload with FileStack</title> <script src="//static.filestackapi.com/filestack-js/3.x.x/filestack.min.js"></script> <meta charset="UTF-8" /> </head> <body> Upload an image <button id="upload">upload</button> <script> const uploadButton = document.getElementById("upload"); const client = filestack.init("ADD_YOUR_API_KEY"); uploadButton.addEventListener("click", (event) => { const options = { accept: ["image/*"], onFileUploadFinished: () => { alert("Image uploaded Successfully!"); } }; client.picker(options).open(); }); </script> </body> </html> Check out the . You will need to create your own for the demo to upload the file. demo on CodeSandbox Filestack API key This is all the code required to create a simple uploader that accepts images and uploads the image to . Filestack's CDN When the user clicks on the upload button, Filestack presents them with an interactive widget that allows the user the ability to upload from multiple sources and also allows them to crop or rotate before uploading. Filestack also provides you with a that let you customize almost every aspect of the File Picker, including the ability to customize file sources, set the minimum and maximum number of files that can be uploaded, set the required dimensions of the image to be uploaded, etc. wide variety of options Conclusion In conclusion, this article has provided an in-depth exploration of file handling in JavaScript on the web. We delved into the intricacies of working with files, starting with the Blob object and understanding how to accept files from users through file input. We also looked at a basic example of uploading files to a server and displaying the progress as the file gets uploaded to the user. Additionally, we discussed the limitations of creating a file management system from scratch and saw why you should probably consider using a cloud-based storage solution like Filestack to streamline file handling in your applications.