32

Typically, HTML pages can have link to documents (PDF, etc...) which can be downloaded from the server.

Assuming a Javascript enabled webpage, is it possible to dynamically create a text document (for example) from within the user browser and add a link to download this document without a round trip to the server (or a minimal one)?

In other word, the user would click on a button, the javascript would generate randoms numbers (for example), and put them in a structure. Then, the javascript (JQuery for example) would add a link to the page to download the result as a text file from the structure.

This objective is to keep all (or at least most) of the workload on the user side.

Is this feasible, if yes how?

Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
  • now **2015** we can use **[Blob (MDN link)](https://developer.mozilla.org/en-US/docs/Web/API/Blob)** to build URL to download any data created dynamically. – befzz Jun 18 '15 at 22:48

3 Answers3

45

Here's a solution I've created, that allows you to create and download a file in a single click:

<html>
<body>
    <button onclick='download_file("my_file.txt", dynamic_text())'>Download</button>
    <script>
    function dynamic_text() {
        return "create your dynamic text here";
    }

    function download_file(name, contents, mime_type) {
        mime_type = mime_type || "text/plain";

        var blob = new Blob([contents], {type: mime_type});

        var dlink = document.createElement('a');
        dlink.download = name;
        dlink.href = window.URL.createObjectURL(blob);
        dlink.onclick = function(e) {
            // revokeObjectURL needs a delay to work properly
            var that = this;
            setTimeout(function() {
                window.URL.revokeObjectURL(that.href);
            }, 1500);
        };

        dlink.click();
        dlink.remove();
    }
    </script>
</body>
</html>

I created this by adapting the code from this HTML5 demo and messing around with things until it worked, so I'm sure there are problems with it (please comment or edit if you have improvements!) but it's a working, single-click solution.

(at least, it works for me on the latest version of Chrome in Windows 7)

ahuff44
  • 1,100
  • 1
  • 9
  • 9
  • Awesome... will award the bounty in 23 hours and 55 mins... – Jodes Aug 01 '16 at 20:12
  • 3
    This should be the accepted answer. It shows the 'hard' work of creating the data URI. Not just saying you need to use them. – pseudosavant Aug 02 '16 at 17:32
  • 4
    For Firefox, you need document.body.appendChild(dlink) after calling createElement() and then presumably document.body.removeChild(dlink) after dlink.remove(). – Alexander Pruss Apr 18 '17 at 14:41
  • 1
    Tested Firefox : document.body.appendChild(dlink) needed but no need to removeChild, the remove() is enough. Thank you ahuff & alexander ! – Eta Feb 07 '18 at 14:32
  • just checked on Chrome Version 73.0.3683.103 (Official Build) (64-bit), WORKS! – Mehar Charan Sahai Apr 19 '19 at 03:45
  • You can use [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) to avoid `var that = this;`. – nice_dev Jul 24 '19 at 12:20
  • I believe that browsers will not honor the download attribute if the file is a PDF, and instead do whatever the browser settings say they will do for PDFs, this is true at least for chrome – Charles L. Mar 30 '21 at 21:16
15

By appending a data URI to the page, you can embed a document within the page that can be downloaded. The data portion of the string can be dynamically concatenated using Javascript. You can choose to format it as a URL encoded string or as base64 encoded. When it is base64 encoded, the browser will download the contents as a file. You will have to add a script or jQuery plugin to do the encoding. Here is an example with static data:

jQuery('body').prepend(jQuery('<a/>').attr('href','data:text/octet-stream;base64,SGVsbG8gV29ybGQh').text('Click to download'))
Nate Barr
  • 4,640
  • 2
  • 25
  • 21
  • 1
    This won't work in IE and Edge: http://caniuse.com/#feat=datauri – Limon Monte Oct 18 '15 at 10:53
  • That is incorrect. It will work in IE and Edge for download links. It will not work in IE/Edge for page assets like HTML and CSS files. You could download CSS though, just not use it in a `` tag. – pseudosavant Aug 02 '16 at 17:31
10

A PDF file? No. A txt file. Yes. With the recent HTML5 blob URIs. A very basic form of your code would look something like this:

window.URL = window.webkitURL || window.URL;
window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder;
var file = new window.BlobBuilder(),
    number = Math.random().toString(); //In the append method next, it has to be a string
file.append(number); //Your random number is put in the file

var a = document.createElement('a');
a.href = window.URL.createObjectURL(file.getBlob('text/plain'));
a.download = 'filename.txt';
a.textContent = 'Download file!';
document.body.appendChild(a);

You can use the other methods mentioned in the other answers as a fallback, perhaps, since BlobBuilder probably isn't supported very well.

Demo

Note: BlobBuilder seems to be deprecated. Refer to this answer to see how to use Blob instead of BlobBuilder. Thanks to @limonte for the heads up.

Some Guy
  • 15,854
  • 10
  • 58
  • 67