JavaScript – Creating A Downloadable File in the Browser

Let’s say that you have an array of arrays that is dynamically generated and you would like to provide a download link/button to download it as a CSV. How would you go about doing it? Ordinarily you would go about sending the data to the server which would then be able to make a downloadable version of the data. Believe it or not, there is also a way to do it in modern browsers without ever needing to make additional requests to a server. The following JSBin proves this by providing a large textarea that can be modified and a download link which when clicked (in modern browsers) will download a file with the specified contents:
JS Bin

How does it work? We basically just rely on data URIs. For instance, clicking here should result in downloading a file with text saying Hello World!!!. This an simply an anchor element (<a>) with an href of data:text/plain;charset=utf-8,Hello%20world!!!. In addition, some newer browsers (Chrome and FireFox) support the download attribute being set to specify the default file name when downloaded.

How do you get it to be dynamic? You can simply modify the href attribute when the link is clicked, by binding the necessary code to the click event of the link. Here is a simple version of the JSBin shown:

<!DOCTYPE html>
<html>
  <head>
    <style type="text/css">...</style>
    <script type="text/JavaScript">
    window.onload = function() {
      var txt = document.getElementById('txt');
      txt.value = window.onload + '';
      document.getElementById('link').onclick = function(code) {
        this.href = 'data:text/plain;charset=utf-8,'
          + encodeURIComponent(txt.value);
      };
    };

    main();
    </script>
  </head>
  <body>
    <div id="txtWrap">
      <textarea id="txt"></textarea>
    </div>
    <a href="" id="link" download="code.txt">Download Above Code</a>
  </body>
</html>

Ignoring the omitted CSS rules, you will notice that the concept is quite simple. The one thing you want to remember is that in order to make sure that all characters are downloaded correctly you will want to use encodeURIComponent(). I have seen implementations that use escape(), but that function is deprecated and doesn’t always encode the characters correctly.

Have fun making your quick custom download buttons :cool:

12 thoughts on “JavaScript – Creating A Downloadable File in the Browser”

    1. I think the only thing you’d really have to be careful about is that you’re injecting the raw data into the browser itself. The `href` attribute is literally holding the data that the user is downloading. As you’ll see sometimes with base 64 image files, having too much there can cause a strain on the client side. So while there might not be a browser limitation size-wise, you definitely want to be careful with how much data you’re storing there.

    2. Looks like it’s 4GB in modern browsers. Caniuse specifies that IE8 limited it to 32kb and IE9 upped it to 4GB. A quick browse around doesn’t give specific numbers for other browsers, so a reasonable conclusion is that IE’s numbers were called out because IE8 differed from spec, but IE9 fixed that.

      Obviously, when you start getting up that high, there are some serious performance issues to think about. A 2GB binary, encoded to B64, is going to be about a 2.6GB data URI that is essentially part of the memory being used by the window. Even if the browser is technically capable of handling that, you’ve got Chrome, Safari, and IE running on mobile devices with less than that much RAM in total, and definitely less than that much free RAM.

      I’d say that the max theoretical size is probably an order of magnitude bigger than the max advisable size.

  1. Nice and helpful post.
    However, I would have liked to see a bit about browser support and limitations (e.g. filesize like opensas mentioned).

  2. Interesting idea!

    I was thinking about how to overwork the .ics file compiled from the microdata of our homepage.
    So maybe it is possible to create it on-the-fly using your trick …

    Will have to test it on my FirefoxOS device and another one’s Android one, though.

Leave a Reply

Your email address will not be published. Required fields are marked *


two + = 4

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="">