1096

Is there a way to create a text file on the client side and prompt the user to download it without any interaction with the server?

I know I can't write directly to their machine (security and all), but can I create the file and prompt them to save it?

Eflyax
  • 5,307
  • 2
  • 19
  • 29
Joseph Silber
  • 214,931
  • 59
  • 362
  • 292
  • 6
    See also: [JavaScript: Create and save file](https://stackoverflow.com/a/53864791/8068625) – Henry Woody Mar 22 '19 at 22:40
  • 4
    As of April 2014, FileSytem APIs may not be standardized in W3C. Anyone looking at the solution with blob should thread with caution, I guess. [HTML5 rocks heads up](http://www.html5rocks.com/en/tutorials/file/filesystem/) [W3C Mailing List on FileSytem API](http://lists.w3.org/Archives/Public/public-webapps/2014AprJun/0010.html) – pravin Jan 20 '15 at 15:47

22 Answers22

987

Simple solution for HTML5 ready browsers...

function download(filename, text) {
  var element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  element.setAttribute('download', filename);

  element.style.display = 'none';
  document.body.appendChild(element);

  element.click();

  document.body.removeChild(element);
}
form * {
  display: block;
  margin: 10px;
}
<form onsubmit="download(this['name'].value, this['text'].value)">
  <input type="text" name="name" value="test.txt">
  <textarea name="text"></textarea>
  <input type="submit" value="Download">
</form>

Usage

download('test.txt', 'Hello world!');
mikemaccana
  • 110,530
  • 99
  • 389
  • 494
Matěj Pokorný
  • 16,977
  • 5
  • 39
  • 48
  • 13
    Yep. This is exactly what @MatthewFlaschen has [posted here about 3 years ago](http://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-server/18197341?noredirect=1#answer-3665147). – Joseph Silber Aug 12 '13 at 22:01
  • 66
    Yes, but with `download` attribute you can specify file name ;-) – Matěj Pokorný Aug 12 '13 at 22:08
  • 3
    As @earcam has already pointed out [in the comments above](http://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-server/18197341?noredirect=1#comment-16342145). – Joseph Silber Aug 13 '13 at 00:30
  • 6
    Chrome only appends the `txt` extension if you do not provide an extension in the filename. If you do `download("data.json", data)` it'll work as expected. – Carl Smith Jul 19 '14 at 14:34
  • In chrome if I use your code outside a submit form, and named my file *.js for example, chrome tell me its a malware. Any idea how to fix this ? – Scotow May 18 '16 at 17:22
  • @Scotow Same situation with [this fiddle](https://jsfiddle.net/2aLxwcq9/)? Maybe this is related: [Malware and unwanted software](https://support.google.com/webmasters/answer/3258249) – Matěj Pokorný May 19 '16 at 13:48
  • This will remove any newline in the downloaded text. My file only contains 1 line. Any Idea on how to fix that? If I do `data:text/plain;base64` firefox won't download it. – Gasp0de Mar 06 '18 at 09:23
  • @Gasp0de You are opening that file in Windows Notepad. Am I right? Try Sublime Text, VSCode, Atom, Notepad++, etc. Notepad expecting, that lines ends with sequence \n\r, but this method saves new lines as \n only. – Matěj Pokorný Mar 06 '18 at 09:49
  • @MatějPokorný I am using Notepad++. I have also tried `JSON.stringify(item, undefined, "\t").replace(/\n/g, "\r\n");`. When I print the text on the console, immediately before inserting it into the data uri, I can see that it contains \r\n, however, when I open the saved file those are gone. I think I better open an own question. – Gasp0de Mar 06 '18 at 10:00
  • I opened an own question here: https://stackoverflow.com/questions/49128196/downloading-json-including-newline-characters-via-data-uri – Gasp0de Mar 06 '18 at 10:08
  • 9
    This worked for me in Chrome (73.0.3683.86), and Firefox (66.0.2). It did **NOT** work in IE11 (11.379.17763.0) and Edge (44.17763.1.0). – Sam Mar 29 '19 at 08:40
  • How can I do this with a jpeg or png file? – chovy May 03 '19 at 06:44
  • Does it work for Mobile App or Mobile browser? I have tried this for iPhone Safari browser, but It does not download the file in download folder – Hardik Darji Oct 14 '19 at 06:57
  • 3
    There's no need to attach the element to the DOM. – sean Dec 06 '19 at 14:04
  • 1
    @sean is right, remove `document.body.appendChild(element);` and `document.body.removeChild(element);`, works just as well. – Connor Low Jun 13 '20 at 17:07
  • if i have to send formData in this, how will i send that – FrontEndDeveloper Apr 08 '21 at 08:38
  • works for me using Chrome, but oddly, all UI elements are empty at the end. I wonder why. – Ludovic Aubert May 13 '21 at 16:43
  • This method will cause problems with very large files. Look at the other answers that use URL.createObjectURL for more performant and stable solution. – Code Commander Aug 14 '22 at 21:33
  • will this also work with other file types f.e. mp3? would the data attribute be "audio/mp3" then? – tikej Sep 20 '22 at 21:59
  • holy crap it worked! – Dan Mantyla Oct 24 '22 at 22:21
  • I wonder if you can do this with rtf, pdf as well (just in plain javascript) – Wim den Herder Jan 17 '23 at 09:41
  • This no longer works under Chrome. Apparently for security reasons. Error message is "Uncaught DOMException: Failed to read the 'localStorage' property from 'Window': The document is sandboxed and lacks the 'allow-same-origin' flag." – James Newton May 26 '23 at 22:01
481

You can use data URIs. Browser support varies; see Wikipedia. Example:

<a href="data:application/octet-stream;charset=utf-16le;base64,//5mAG8AbwAgAGIAYQByAAoA">text file</a>

The octet-stream is to force a download prompt. Otherwise, it will probably open in the browser.

For CSV, you can use:

<a href="data:application/octet-stream,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A">CSV Octet</a>

Try the jsFiddle demo.

Tom Burris
  • 380
  • 2
  • 19
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 21
    This is not a cross browser solution but definitely something worth looking at. For example IE limits support to data uri. IE 8 limits size to 32KB and IE 7 and lower doesn't support at all. – Darin Dimitrov Sep 08 '10 at 06:32
  • @Darin, yes, this won't work in any version of IE, because data URIs are not allowed in `a` elements. – Matthew Flaschen Sep 08 '10 at 06:35
  • 9
    in Chrome Version 19.0.1084.46, this method generates the following warning : "Resource interpreted as Document but transferred with MIME type text/csv: "data:text/csv,field1%2Cfield2%0Afoo%2Cbar%0Agoo%2Cgai%0A"." A download is not triggered – Chris May 16 '12 at 11:44
  • 1
    @Chris, yes, apparently it doesn't work in Chrome, even with octet-stream. – Matthew Flaschen May 16 '12 at 14:53
  • 3
    It does work in Chrome now (tested against v20 and v21) but not IE9 (that might just be the jsFiddle, but somehow I doubt it). – earcam Aug 30 '12 at 16:20
  • I'm accepting this answer, since there seems to be no other way to accomplish this... – Joseph Silber Nov 09 '12 at 19:56
  • 1
    Does not work in ie8 and ie9 because these browsers only support data uri for images. Ref: http://stackoverflow.com/questions/12042847/data-uri-file-download-in-interent-explorer – Jean-Philippe Martin Mar 08 '13 at 15:44
  • 1
    As naren noted with his answer, Firefox needs the link to be present in the document in order for the download to occur. – Teepeemm Apr 30 '14 at 15:59
  • 2
    Doesn't work at all in Safari (7.0.4). Also, as of Chrome 36.0.1985.97 beta it doesn't seem possible to name the file using the download attribute. – jasongonzales Jul 02 '14 at 15:35
  • Also, using Chrome 37.0.2062.120, the browser crashes when the base64 string gets too long. – Rudey Sep 11 '14 at 13:47
  • I was like - who is that linking to wikipedia for browser compat - oh ok :) – Milimetric Sep 12 '14 at 18:41
  • 7
    The correct charset is almost certainly UTF-16, unless you have code converting it to UTF-8. JavaScript uses UTF-16 internally. If you have a text or CSV file, start the string with '\ufeff', the Byte Order Mark for UTF-16BE, and text editors will be able to read non-ASCII characters correctly. – larspars Nov 19 '14 at 09:06
  • @larspars, good point. It is possible to make a UTF-8 data URL (and my example was one), but probably easier to make a UTF-16 one. Technically, though, JavaScript is closer to UCS-2. – Matthew Flaschen Nov 20 '14 at 01:10
  • Does not data URIs have size limitations? – Avinav May 22 '15 at 15:53
  • @Avinav, yes, at least in certain browsers (e.g. IE 8). – Matthew Flaschen May 30 '15 at 23:16
  • if there a way to give an understandable name to an image whose src is a data URI? – Sheraff Nov 22 '15 at 15:35
  • Does not work in Samsung Browser (Default mobile browser) – Alex Dec 22 '15 at 14:49
  • 26
    Just add download="txt.csv" attribute in order to have proper file name and extension and to tell your OS what to do with it. – elshnkhll Jan 15 '16 at 16:33
  • And there is a size limit. It is said that for Chrome, the limit is 2MB. – gm2008 Aug 11 '16 at 16:46
  • Works like a charm on Chrome. base64 seems to be the best solution to pass PDF files :) – Jerry Nov 22 '16 at 21:53
  • 1
  • It does not work in Microsoft Edge 40.15063.674.0 and Internet Explorer 11.674.15063.0. I used the answer from @naren and it works. – drinovc Nov 08 '17 at 16:43
  • I'm trying to use this to download the value of a textarea as a text file but the newlines in the textarea are not shown in the downloaded text file. Suggestions? Here is how I form the href: 'data:application/octet-stream,' + encodeURIComponent(document.getElementById("editor").value).replace("\n","%0A") . (I added the replace function hoping that might be the issue). – youcantryreachingme Feb 25 '18 at 02:12
  • 1
    No longer works in Firefox; top level data URIs have been blocked for "security". https://bugzilla.mozilla.org/show_bug.cgi?id=1331351 – James M Oct 01 '18 at 13:04
  • It work great in Firefox for me, but note that **DataURI's are subject to size limitations**, which vary by browser maybe 32kb, maybe 100kb, maybe 4gb (good luck finding a straight answer on actual limits!) – ashleedawg Dec 09 '21 at 08:42
  • This is not a viable solution. I would rather create a Blob with the proper mime type, then add it to an anchor tag which I will trigger a click on. The advantage of this solution is that you don't have to explicitly create an ObjectUrl. – asiby Oct 25 '22 at 14:50
318

An example for IE 10+, Firefox and Chrome (and without jQuery or any other library):

function save(filename, data) {
    const blob = new Blob([data], {type: 'text/csv'});
    if(window.navigator.msSaveOrOpenBlob) {
        window.navigator.msSaveBlob(blob, filename);
    }
    else{
        const elem = window.document.createElement('a');
        elem.href = window.URL.createObjectURL(blob);
        elem.download = filename;        
        document.body.appendChild(elem);
        elem.click();        
        document.body.removeChild(elem);
    }
}

Note that, depending on your situation, you may also want to call URL.revokeObjectURL after removing elem. According to the docs for URL.createObjectURL:

Each time you call createObjectURL(), a new object URL is created, even if you've already created one for the same object. Each of these must be released by calling URL.revokeObjectURL() when you no longer need them. Browsers will release these automatically when the document is unloaded; however, for optimal performance and memory usage, if there are safe times when you can explicitly unload them, you should do so.

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319
Ludovic Feltz
  • 11,416
  • 4
  • 47
  • 63
  • In Chrome, I didn't actually have to append the element to the body to get this to work. – JackMorrissey Jul 05 '16 at 16:29
  • There is a size limit. For Chrome, it is said to be 2MB. Anyone has idea on how to deal with larger file? – gm2008 Aug 11 '16 at 16:48
  • Calling `window.URL.revokeObjectURL(elem.href);` after removing `elem` on Firefox 48 results in the download window never appearing and the download never starting. Removing the call to `revokeObjectURL()` solves this. For AngularJS 1.x apps, I guess that you can build an array of Urls that are cleaned up on destroy of the controller. – Splaktar Sep 06 '16 at 17:55
  • 2
    For AngularJS 1.x apps, you can build an array of Urls as they are created and then clean them up in the $onDestroy function of the component. This is working great for me. – Splaktar Sep 06 '16 at 18:12
  • This combines [naren's solution](http://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-server/20194533#20194533), with [Dzarek's](http://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-server/19856861#19856861) handling of IE. – Dan Dascalescu Nov 05 '16 at 21:06
  • 2
    Other answers led to `Failed: network error` in Chrome. This one works well. – juniper- Sep 27 '17 at 19:25
  • "All the above solutions didn't work in all browsers". Since the order of answers can change over time, it's unclear which answers were above yours when you wrote this. Can you indicate exactly which approaches don't work in all browsers? – Kevin Apr 02 '18 at 18:57
  • 6
    This worked for me in Chrome (73.0.3683.86), Firefox (66.0.2), IE11 (11.379.17763.0) and Edge (44.17763.1.0). – Sam Mar 29 '19 at 08:41
  • [Kanchu's solution on the duplicate of this question](https://stackoverflow.com/a/30832210/798371) includes some small improvements. – WBT May 21 '19 at 15:33
  • that bypasses the URI size limit. – tstoev Oct 28 '19 at 17:10
  • 5
    For those looking to avoid garbage collection on the URL or strange behavior, just declare your blob like this: `const url = URL.createObjectURL(blob, { oneTimeOnly: true })`. You can always save the blob and generate a new Url later if needed. – Daniel May 01 '20 at 21:10
  • 5
    Consider adding `elem.style.display = 'none';` before `document.body.appendChild(elem);` if you want to avoid any potential for visual glitches – JamesTheAwesomeDude Jul 29 '20 at 21:30
  • msSaveOrOpenBlob seems to be deprecated. So I think you shoud edit this answer. https://developer.mozilla.org/en-US/docs/Web/API/Navigator/msSaveOrOpenBlob – ippachi Oct 27 '21 at 07:38
  • @ippachi You are right, it's compatible with older version of Internet Explorer. But that's for this reason that it is in this answer, to be compatible with many browser. If the function doesn't exist in the browser `createObjectURL` will be called instead. – Ludovic Feltz Oct 27 '21 at 08:16
202

All of the above example works just fine in chrome and IE, but fail in Firefox. Please do consider appending an anchor to the body and removing it after click.

var a = window.document.createElement('a');
a.href = window.URL.createObjectURL(new Blob(['Test,Text'], {type: 'text/csv'}));
a.download = 'test.csv';

// Append anchor to body.
document.body.appendChild(a);
a.click();

// Remove anchor from body
document.body.removeChild(a);
HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
naren
  • 14,611
  • 5
  • 38
  • 45
  • 5
    However: there's [an open bug in IE 10 (and I've still seen it in 11)](https://connect.microsoft.com/IE/feedback/details/797361/ie-10-treats-blob-url-as-cross-origin-and-denies-access) that throws "Access is denied" on the `a.click()` line because it thinks the blob URL is cross-origin. – Matt Dec 16 '14 at 19:44
  • 1
    @Matt data uri is cross origin in some browsers. as far as I know, not just in msie, but in chrome as well. you can test it by trying to inject javascript with data uri. It won't be able to access other parts of the site... – inf3rno Sep 13 '15 at 00:13
  • 11
    "All of the above example works just fine in chrome and IE, but fail in Firefox.". Since the order of answers can change over time, it's unclear which answers were above yours when you wrote this. Can you indicate exactly which approaches don't work in Firefox? – Kevin Apr 02 '18 at 18:57
  • 2
    This blob approach works much better for very large files. – joe Jul 29 '20 at 13:05
136

I'm happily using FileSaver.js. Its compatibility is pretty good (IE10+ and everything else), and it's very simple to use:

var blob = new Blob(["some text"], {
    type: "text/plain;charset=utf-8;",
});
saveAs(blob, "thing.txt");
Daniel Buckmaster
  • 7,108
  • 6
  • 39
  • 57
37

Use Blob:

function download(content, mimeType, filename){
  const a = document.createElement('a') // Create "a" element
  const blob = new Blob([content], {type: mimeType}) // Create a blob (file-like object)
  const url = URL.createObjectURL(blob) // Create an object URL from blob
  a.setAttribute('href', url) // Set "a" element link
  a.setAttribute('download', filename) // Set download filename
  a.click() // Start downloading
}

Blob is being supported by all modern browsers.
Caniuse support table for Blob:

Here is a Fiddle

And here MDN Docs

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...

Stelios333
  • 498
  • 4
  • 8
22

The following method works in IE11+, Firefox 25+ and Chrome 30+:

<a id="export" class="myButton" download="" href="#">export</a>
<script>
    function createDownloadLink(anchorSelector, str, fileName){
        if(window.navigator.msSaveOrOpenBlob) {
            var fileData = [str];
            blobObject = new Blob(fileData);
            $(anchorSelector).click(function(){
                window.navigator.msSaveOrOpenBlob(blobObject, fileName);
            });
        } else {
            var url = "data:text/plain;charset=utf-8," + encodeURIComponent(str);
            $(anchorSelector).attr("download", fileName);               
            $(anchorSelector).attr("href", url);
        }
    }

    $(function () {
        var str = "hi,file";
        createDownloadLink("#export",str,"file.txt");
    });

</script>

See this in Action: http://jsfiddle.net/Kg7eA/

Firefox and Chrome support data URI for navigation, which allows us to create files by navigating to a data URI, while IE doesn't support it for security purposes.

On the other hand, IE has API for saving a blob, which can be used to create and download files.

dinesh ygv
  • 1,840
  • 1
  • 14
  • 18
  • 1
    I just used jquery to attach events(onclick and onready) and set attributes, which you can also do with vanilla JS. The core part(window.navigator.msSaveOrOpenBlob) doesn't need jquery. – dinesh ygv Nov 06 '16 at 02:17
  • 1
    There is still the limitation of size for the data uri approach, isn't it? – phil Jun 26 '17 at 08:21
  • msSaveOrOpenBlob is shown as obsolete here: https://developer.mozilla.org/en-US/docs/Web/API/Navigator/msSaveBlob – eflat May 14 '20 at 00:30
21

We can use the URL api, in particular URL.createObjectURL(), and the Blob api to encode and download pretty much anything.

If your download is small, this works fine:

document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify("HELLO WORLD", null, 2)]))}"> Click me</a>`
download.click()
download.outerHTML = ""

If your download is huge, instead of using the DOM, a better way is to create a link element with the download parameters, and trigger a click.

Notice the link element isn't appended to the document but the click work anyway! This is possible to create a download of many hundreds of Mo this way, as the DOM is not modified (Otherwise the huge URL in the DOM can be a source of tab freeze).

const stack = {
 some: "stuffs",
 alot: "of them!"
}

BUTTONDOWNLOAD.onclick = (function(){
  let j = document.createElement("a")
  j.download = "stack_"+Date.now()+".json"
  j.href = URL.createObjectURL(new Blob([JSON.stringify(stack, null, 2)]))
  j.click()
})
<button id="BUTTONDOWNLOAD">DOWNLOAD!</button>

Bonus! Download any cyclic objects, avoid the errors:

TypeError: cyclic object value (Firefox) TypeError: Converting

circular structure to JSON (Chrome and Opera) TypeError: Circular

reference in value argument not supported (Edge)

Using https://github.com/douglascrockford/JSON-js/blob/master/cycle.js

On this example, downloading the document object as json.

/* JSON.decycle */
if(typeof JSON.decycle!=="function"){JSON.decycle=function decycle(object,replacer){"use strict";var objects=new WeakMap();return(function derez(value,path){var old_path;var nu;if(replacer!==undefined){value=replacer(value)}
if(typeof value==="object"&&value!==null&&!(value instanceof Boolean)&&!(value instanceof Date)&&!(value instanceof Number)&&!(value instanceof RegExp)&&!(value instanceof String)){old_path=objects.get(value);if(old_path!==undefined){return{$ref:old_path}}
objects.set(value,path);if(Array.isArray(value)){nu=[];value.forEach(function(element,i){nu[i]=derez(element,path+"["+i+"]")})}else{nu={};Object.keys(value).forEach(function(name){nu[name]=derez(value[name],path+"["+JSON.stringify(name)+"]")})}
return nu}
return value}(object,"$"))}}


document.body.innerHTML += 
`<a id="download" download="PATTERN.json" href="${URL.createObjectURL(new Blob([JSON.stringify(JSON.decycle(document), null, 2)]))}"></a>`
download.click()
NVRM
  • 11,480
  • 1
  • 88
  • 87
17

The package js-file-download from github.com/kennethjiang/js-file-download handles edge cases for browser support:

View source to see how it uses techniques mentioned on this page.

Installation

yarn add js-file-download
npm install --save js-file-download

Usage

import fileDownload from 'js-file-download'

// fileDownload(data, filename, mime)
// mime is optional

fileDownload(data, 'filename.csv', 'text/csv')
Beau Smith
  • 33,433
  • 13
  • 94
  • 101
16

This solution is extracted directly from tiddlywiki's (tiddlywiki.com) github repository. I have used tiddlywiki in almost all browsers and it works like a charm:

function(filename,text){
    // Set up the link
    var link = document.createElement("a");
    link.setAttribute("target","_blank");
    if(Blob !== undefined) {
        var blob = new Blob([text], {type: "text/plain"});
        link.setAttribute("href", URL.createObjectURL(blob));
    } else {
        link.setAttribute("href","data:text/plain," + encodeURIComponent(text));
    }
    link.setAttribute("download",filename);
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
}

Github repo: Download saver module

Danielo515
  • 5,996
  • 4
  • 32
  • 66
  • 1
    It works very nicely on Chrome, but not on Firefox. It does make a file and downloads it, but the file is empty. No content. Any ideas why? Haven't tested on IE... – Narxx Feb 16 '17 at 16:26
  • 4
    except that the function has no name, this is my favourite – Yoraco Gonzales Aug 20 '18 at 20:32
13
function download(filename, text) {
  var element = document.createElement('a');
  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
  element.setAttribute('download', filename);

  element.style.display = 'none';
  document.body.appendChild(element);

  element.click();

  document.body.removeChild(element);
}



// Start file download.
download("hello.txt","This is the content of my file :)");

Original article : https://ourcodeworld.com/articles/read/189/how-to-create-a-file-and-generate-a-download-with-javascript-in-the-browser-without-a-server

pixparker
  • 2,903
  • 26
  • 23
12

If you just want to convert a string to be available for download you can try this using jQuery.

$('a.download').attr('href', 'data:application/csv;charset=utf-8,' + encodeURI(data));
Rick
  • 12,606
  • 2
  • 43
  • 41
  • 2
    Scape data with encodeURI might be needed as I suggested here before being able to comment: http://stackoverflow.com/a/32441536/4928558 – atfornes Jun 15 '16 at 12:31
11

Solution that work on IE10: (I needed a csv file, but it's enough to change type and filename to txt)

var csvContent=data; //here we load our csv data 
var blob = new Blob([csvContent],{
    type: "text/csv;charset=utf-8;"
});

navigator.msSaveBlob(blob, "filename.csv")
Dzarek
  • 539
  • 5
  • 9
  • 2
    [Ludovic's answer](http://stackoverflow.com/questions/3665115/create-a-file-in-memory-for-user-to-download-not-through-server/33542499#33542499) includes this big, plus support for the other browsers. – Dan Dascalescu Nov 05 '16 at 21:10
9

As mentioned before, filesaver is a great package to work with files on the client side. But, it is not do well with large files. StreamSaver.js is an alternative solution (which is pointed in FileServer.js) that can handle large files:

const fileStream = streamSaver.createWriteStream('filename.txt', size);
const writer = fileStream.getWriter();
for(var i = 0; i < 100; i++){
    var uint8array = new TextEncoder("utf-8").encode("Plain Text");
    writer.write(uint8array);
}
writer.close()
Erik
  • 503
  • 1
  • 7
  • 26
Mostafa Barmshory
  • 1,849
  • 24
  • 39
8
var element = document.createElement('a');
element.setAttribute('href', 'data:text/text;charset=utf-8,' +      encodeURI(data));
element.setAttribute('download', "fileName.txt");
element.click();
Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
7

Based on @Rick answer which was really helpful.

You have to scape the string data if you want to share it this way:

$('a.download').attr('href', 'data:application/csv;charset=utf-8,'+ encodeURI(data));

` Sorry I can not comment on @Rick's answer due to my current low reputation in StackOverflow.

An edit suggestion was shared and rejected.

atfornes
  • 468
  • 5
  • 21
3

This below function worked.

 private createDownloadableCsvFile(fileName, content) {
   let link = document.createElement("a");
   link.download = fileName;
   link.href = `data:application/octet-stream,${content}`;
   return link;
 }
giapnh
  • 2,950
  • 24
  • 20
2

Download file with extensions or without extensions in the example, I am using JSON. You may add your data and extensions. You may use 'MAC-Addresses.json' here, as per your wish. If you want to add an extension, add there, else, just write the file name without extensions.

let myJson = JSON.stringify(yourdata);
    let element = document.createElement('a');
    element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(myJson));
    element.setAttribute('download', 'MAC-Addresses.json');
    element.style.display = 'none';
    document.body.appendChild(element);
    element.click();
    document.body.removeChild(element);
Sweta Jain
  • 3,248
  • 6
  • 30
  • 50
Subhan Ali
  • 21
  • 2
1

For me this worked perfectly, with the same filename and extension getting downloaded

<a href={"data:application/octet-stream;charset=utf-16le;base64," + file64 } download={title} >{title}</a>

'title' is the file name with extension i.e, sample.pdf, waterfall.jpg, etc..

'file64' is the base64 content something like this i.e, Ww6IDEwNDAsIFNsaWRpbmdTY2FsZUdyb3VwOiAiR3JvdXAgQiIsIE1lZGljYWxWaXNpdEZsYXRGZWU6IDM1LCBEZW50YWxQYXltZW50UGVyY2VudGFnZTogMjUsIFByb2NlZHVyZVBlcmNlbnQ6IDcwLKCFfSB7IkdyYW5kVG90YWwiOjEwNDAsIlNsaWRpbmdTY2FsZUdyb3VwIjoiR3JvdXAgQiIsIk1lZGljYWxWaXNpdEZsYXRGZWUiOjM1LCJEZW50YWxQYXltZW50UGVyY2VudGFnZSI6MjUsIlByb2NlZHVyZVBlcmNlbnQiOjcwLCJDcmVhdGVkX0J5IjoiVGVycnkgTGVlIiwiUGF0aWVudExpc3QiOlt7IlBhdGllbnRO

abdul
  • 340
  • 6
  • 18
1

I would use an <a></a> tag then set the href='path'. Afterwards, place an image in between the <a> elements so that I can have a visual to see it. If you wanted to, you could create a function that will change the href so that it won't just be the same link but be dynamic.

Give the <a> tag an id as well if you want to access it with javascript.

Starting with the HTML Version:

<a href="mp3/tupac_shakur-how-do-you-want-it.mp3" download id="mp3Anchor">
     <img src="some image that you want" alt="some description" width="100px" height="100px" />
</a>

Now with JavaScript:

*Create a small json file*;

const array = [
     "mp3/tupac_shakur-how-do-you-want-it.mp3",
     "mp3/spice_one-born-to-die.mp3",
     "mp3/captain_planet_theme_song.mp3",
     "mp3/tenchu-intro.mp3",
     "mp3/resident_evil_nemesis-intro-theme.mp3"
];

//load this function on window
window.addEventListener("load", downloadList);

//now create a function that will change the content of the href with every click
function downloadList() {
     var changeHref=document.getElementById("mp3Anchor");

     var j = -1;

     changeHref.addEventListener("click", ()=> {

           if(j < array.length-1) {
               j +=1;
               changeHref.href=""+array[j];
          }
           else {
               alert("No more content to download");
          }
}
Das_Geek
  • 2,775
  • 7
  • 20
  • 26
darrell
  • 63
  • 1
  • 4
1

The following method works in IE10+, Edge, Opera, FF and Chrome:

const saveDownloadedData = (fileName, data) => {
    if(~navigator.userAgent.indexOf('MSIE') || ~navigator.appVersion.indexOf('Trident/')) { /* IE9-11 */
        const blob = new Blob([data], { type: 'text/csv;charset=utf-8;' });
        navigator.msSaveBlob(blob, fileName);
    } else {
        const link = document.createElement('a')
        link.setAttribute('target', '_blank');
        if(Blob !== undefined) {
            const blob = new Blob([data], { type: 'text/plain' });
            link.setAttribute('href', URL.createObjectURL(blob));
        } else {
            link.setAttribute('href', 'data:text/plain,' + encodeURIComponent(data));
        }

        ~window.navigator.userAgent.indexOf('Edge')
            && (fileName = fileName.replace(/[&\/\\#,+$~%.'':*?<>{}]/g, '_')); /* Edge */

        link.setAttribute('download', fileName);
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
    }
}

So, just call the function:

saveDownloadedData('test.txt', 'Lorem ipsum');
Denys Rusov
  • 560
  • 6
  • 6
-26

If the file contains text data, a technique I use is to put the text into a textarea element and have the user select it (click in textarea then ctrl-A) then copy followed by a paste to a text editor.

HBP
  • 15,685
  • 6
  • 28
  • 34
  • 40
    I had considered that, but from a user-friendliness point, this is disastrous. Also, the file has to be saved with a CSV extension. Try telling that to your users. – Joseph Silber Sep 08 '10 at 07:07