Create file downloads with plain browser JavaScript

Data is the heart of many applications. Users interact with data constantly, and the real value of many web apps is the simplicity with which they allow users to interact with their data.

One way to make data management more convenient is to just allow users to download the data they’re working with. In a world overrun with cloud computing, this sounds very old school. Still, there’s a time and place for everything.

We have a secret weapon for creating file downloads using only browser technology: the anchor tag’s download attribute. Check it out:

<a href="/files/nvc89340nc.txt"
   download="pretty-file-name.txt">
  Download
</a>

Notice several details about the above code snippet:

  • This is a regular anchor tag, the same one we use to create hyperlinks
  • It has an href attribute pointing to a file on the server
  • It has a download attribute that specifies a filename that will be suggested when the file is downloaded

When I click this link, I am initiating a download of the file /files/nvc89340nc.txt on the server. When the “Save” dialog appears, it will suggest that I save the file as pretty-file-name.txt.

That’s great, but remember our use case: we don’t have a server. We want to take data that was created and manipulated in JavaScript and allow users to download it onto their personal machines.

There are two good ways to do that, depending on your use case. The first is to use a Blob and corresponding object URL. The second is to use a Data URL. Either option will allow you to turn JavaScript strings into files that can be downloaded by clicking a link.

Blob and Object URL

First, the code:

// Generates a text file download named `filename` with contents of `dataString`.
const generateDownload = (filename, dataString) => {
  const a = document.createElement('a')
  document.body.appendChild(a)
  a.style = 'display: none'
  const blob = new Blob([dataString], {type: 'octet/stream'}),
        url = URL.createObjectURL(blob)
  a.href = url
  a.download = filename
  a.click()
  window.webkitURL.revokeObjectURL(url)
  a.parentElement.removeChild(a)
}

In this example, we first create an anchor to click and a Blob to contain our data. Then we create an object URL that references our Blob and assign that URL to our link’s href attribute. Finally, now that we have our data and a URL that points to it, we can “click” our anchor in JavaScript. This initiates the file download.

Afterward, we will clean up by revoking our object URL and removing our temporary link element.

Data URL

This option is more straightforward. As in, it uses less technologies and they are probably easier to understand:

// Generates a text file download named `filename` with contents of `dataString`.
const generateJSONDownload = (filename, dataString) => {
  const data = 'text/json;charset=utf-8,' + encodeURIComponent(dataString)
  const link = document.createElement('a')
  a.style.display = 'none'

  const attrDownload = document.createAttribute('download')
  attrDownload.value = filename
  link.setAttributeNode(attrDownload)

  const attrHref = document.createAttribute('href')
  attrHref.value = 'data:' + data
  link.setAttributeNode(attrHref)

  document.body.append(link)
  link.click()
  link.remove()
}

URLs that begin with data: are Data URLs. They allow us to embed data into a URL. Check the MDN page for more examples.

In this particular example we will create a JSON file download. Data URLs contain the MIME type of their embedded data, which is text/json in the snippet below.

We will use encodeURIComponent to ensure our data can be safely added to the URL. Then we apply that URL to our anchor element’s href, add a download attribute, and click it. Viola! The string of data we provided will now download onto our machine.

Use Cases

This technique is especially valuable for single file HTML tools and bookmarklets, which both have limitations for how data can be stored and retrieved.