Download file on button click with Javascript (updated)

Find out how to generate and then download any files (.txt, .json or .html) just with JavaScript in the Browser. No Server required!

Download file on button click with Javascript (updated)

In the past, if you needed to store data on your computer while working with JavaScript, you may have had to use server-side code or complex HTML. However, the Blob API and the new File System Access API now allow us to easily and efficiently download any file using JavaScript with just a click of a button.

What's a Blob?

MDN says:

The Blob object represents a blob, which is a file-like object of immutable, raw data; they can be read as text or binary data or converted into a ReadableStream so its methods can be used for processing the data.
Blobs can represent data that isn't necessarily in a JavaScript-native format. The Fileinterface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system.

Read more about Blob on MDN.

Blob goes first

As we already know what's a Blob, let's have a look at how to download any data just using JavaScript Blob API.

Consider having a JSON format object which contains some application configurations:

const configuration = [{ active: true, showButton: false }];

Firstly we have to convert out configuration object into a Blob:

const myBlobFile = new Blob(
    [ JSON.stringify(configuration) ], 
    { type: 'text/json;charset=utf-8' }
)

Now, as we have a file blob, we have two ways to download it.

File System Access API (the new way)

The File System Access API is a proposed web API that provides a consistent, high-level interface for reading and writing files on the user's local device. It allows web applications to access files on the user's device in a way that is similar to how native applications do it.

To download our configuration file, in this example, we'll use showSaveFilePicker method:

async saveConfiguration() {
  const opts = {
    types: [{
      description: 'My configuration file',
      suggestedName: 'my-configurations.json',
      accept: {'text/json': ['.json']},
    }],
  };
  const handle = await window.showSaveFilePicker(opts);
  const writable = await handle.createWritable();
  await writable.write(myBlobFile);
  await writable.close();
}

If you need more information about what's happening here, check MDN docs, they have the best explanation 😎.

While this seems to be the best solution to download our file, you should keep in mind the File System Access API is still in the proposal stage and is not yet supported in any browser.

If it is implemented, it would provide a standard way for web applications to access files on the user's local device, making it easier for developers to create web-based file management and storage applications.

URL and Anchor Element (the old way)

To use an old way to download the file, all we need is to create a blob://...  link using URL.createObjectURL method and send myBlobFile as a parameter:

const blobUrl = URL.createObjectURL(myBlobFile);

As we have a blob://... URL, we just simply create an a element with corresponding href attribute:

saveConfiguration() {
  const anchor = document.createElement('a');
  anchor.href = blobUrl;
  anchor.target = "_blank";
  anchor.download = "my-configuration.json";

  // Auto click on a element, trigger the file download
  anchor.click();

  // This is required
  URL.revokeObjectURL(blobUrl);
}

Keep in mind, always do URL.revokeObjectURL(blobUrl) when you don't need that URL anymore. This is very important for performance.

The right solution

We have examined two methods for downloading a file, but which one should we choose?

While the new File System Access API offers a promising solution, it is currently only in the proposal stage and not yet supported by any browsers. Therefore, it is important to consider a more universally compatible option.

No Problem, here's the right solution:

async saveConfiguration() {
    if ('showSaveFilePicker' in window)
        // Use window.showSaveFilePicker() method
    else {
    	// Use URL and Anchor Element
    }
}

On button click, we call saveConfiguration() function. If the browser supports the showSaveFilePicker function, it will be used to save the file. If not, the function will fall back to the tried and tested old method.

Easy, right?

Conclusion

Always use this trick when you need to download any files in the Browser. Don't complicate yourself with any Server-Side code, or third-party libraries anymore.

Thanks for reading!