JavaScript blob filename without link

422,105

Solution 1

The only way I'm aware of is the trick used by FileSaver.js:

  1. Create a hidden <a> tag.
  2. Set its href attribute to the blob's URL.
  3. Set its download attribute to the filename.
  4. Click on the <a> tag.

Here is a simplified example (jsfiddle):

var saveData = (function () {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";
    return function (data, fileName) {
        var json = JSON.stringify(data),
            blob = new Blob([json], {type: "octet/stream"}),
            url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = fileName;
        a.click();
        window.URL.revokeObjectURL(url);
    };
}());

var data = { x: 42, s: "hello, world", d: new Date() },
    fileName = "my-download.json";

saveData(data, fileName);

I wrote this example just to illustrate the idea, in production code use FileSaver.js instead.

Notes

  • Older browsers don't support the "download" attribute, since it's part of HTML5.
  • Some file formats are considered insecure by the browser and the download fails. Saving JSON files with txt extension works for me.

Solution 2

I just wanted to expand on the accepted answer with support for Internet Explorer (most modern versions, anyways), and to tidy up the code using jQuery:

$(document).ready(function() {
    saveFile("Example.txt", "data:attachment/text", "Hello, world.");
});

function saveFile (name, type, data) {
    if (data !== null && navigator.msSaveBlob)
        return navigator.msSaveBlob(new Blob([data], { type: type }), name);
    var a = $("<a style='display: none;'/>");
    var url = window.URL.createObjectURL(new Blob([data], {type: type}));
    a.attr("href", url);
    a.attr("download", name);
    $("body").append(a);
    a[0].click();
    window.URL.revokeObjectURL(url);
    a.remove();
}

Here is an example Fiddle. Godspeed.

Solution 3

Same principle as the solutions above. But I had issues with Firefox 52.0 (32 bit) where large files (>40 MBytes) are truncated at random positions. Re-scheduling the call of revokeObjectUrl() fixes this issue.

function saveFile(blob, filename) {
  if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveOrOpenBlob(blob, filename);
  } else {
    const a = document.createElement('a');
    document.body.appendChild(a);
    const url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = filename;
    a.click();
    setTimeout(() => {
      window.URL.revokeObjectURL(url);
      document.body.removeChild(a);
    }, 0)
  }
}

jsfiddle example

Solution 4

Late, but since I had the same problem I add my solution:

function newFile(data, fileName) {
    var json = JSON.stringify(data);
    //IE11 support
    if (window.navigator && window.navigator.msSaveOrOpenBlob) {
        let blob = new Blob([json], {type: "application/json"});
        window.navigator.msSaveOrOpenBlob(blob, fileName);
    } else {// other browsers
        let file = new File([json], fileName, {type: "application/json"});
        let exportUrl = URL.createObjectURL(file);
        window.location.assign(exportUrl);
        URL.revokeObjectURL(exportUrl);
    }
}

Solution 5

saveFileOnUserDevice = function(file){ // content: blob, name: string
        if(navigator.msSaveBlob){ // For ie and Edge
            return navigator.msSaveBlob(file.content, file.name);
        }
        else{
            let link = document.createElement('a');
            link.href = window.URL.createObjectURL(file.content);
            link.download = file.name;
            document.body.appendChild(link);
            link.dispatchEvent(new MouseEvent('click', {bubbles: true, cancelable: true, view: window}));
            link.remove();
            window.URL.revokeObjectURL(link.href);
        }
    }
Share:
422,105

Related videos on Youtube

Ash Blue
Author by

Ash Blue

Ash has been leading front-end teams for 10+ years in creating award winning websites. Working with agencies, financial, and entertainment. His full stack experience helps him empower teams to create scalable front-end solutions that harmonize communication with the back-end. In addition to mentoring, open source contributions, and organizing development Meetup events. Ash co-authored HTML5 in Action under Manning Publications, writing on interactive media APIs.

Updated on January 06, 2022

Comments

  • Ash Blue
    Ash Blue over 2 years

    How do you set the name of a blob file in JavaScript when force downloading it through window.location?

    function newFile(data) {
        var json = JSON.stringify(data);
        var blob = new Blob([json], {type: "octet/stream"});
        var url  = window.URL.createObjectURL(blob);
        window.location.assign(url);
    }
    

    Running the above code downloads a file instantly without a page refresh that looks like:

    bfefe410-8d9c-4883-86c5-d76c50a24a1d

    I want to set the filename as my-download.json instead.

  • Ash Blue
    Ash Blue over 10 years
    Oddly it seems to be failing when I copy and paste this into CodePen. Although your code seems legit and good codepen.io/ashblue/pen/jEhmH
  • kol
    kol over 10 years
    Your codepen code works for me in Chrome. The json file is saved into the download folder of Chrome.
  • kol
    kol over 10 years
    @AshBlue The "download" attribute needs HTML5. My code is just an example, you could also try the FileSaver.js demo page: eligrey.com/demos/FileSaver.js
  • Ash Blue
    Ash Blue over 10 years
    I'm getting "Failed - No file" on Chrome Windows ver 30. Is it maybe a Windows exclusive bug?
  • kol
    kol over 10 years
    The download works for me on a Windows 7 PC, but I got the "Failed - No file" message on Windows XP. Interestingly, The FileSaver.js demo page is able to download files to XP.
  • kol
    kol over 10 years
    I've found a workaround: if I change the extension to txt, then the download works.
  • kol
    kol over 10 years
    Interestingly, if you repeatedly try to download a txt this way (by pressing the Run button on jsfiddle.net again and again), the download sometimes fails.
  • philx_x
    philx_x about 9 years
    i allready have an <a id="saveToJson">save as JSON</a> link. i do the Blob creatin logic in the $("#saveToJson") callback function but the problem is i can't do this.click() unless the function is gonna run itself over and over again. ps: i don't like to create those hidden workaround filds so i wanted to set the attributes of my element when it's clicked.
  • kol
    kol about 9 years
    @philx_x Since you already have an <a> tag, and create the Blob in its click handler, you don't have to call .click() yourself, because it will cause infinite recursion.
  • kol
    kol over 8 years
    @xheyhenry FileSaver.js should work in IE10+: github.com/eligrey/FileSaver.js/#supported-browsers There is a workaround for IE<10: github.com/eligrey/FileSaver.js/#ie--10
  • manojadams
    manojadams over 6 years
    Just wanted to mention that this solution will not work for files with sizes greater than a particular threshold. e.g-> 2 MB for chrome. This size varies from browser to browser.
  • Adrián Paredes
    Adrián Paredes over 6 years
    This does not work for me because I need to open the file in a new tab. I have to show a PDF in Chrome, but I need to show a user friendly name in the URL toolbar, and if the user wants to download through the download icon, I have to put the same user friendly name in the file.
  • Rafael Andrade
    Rafael Andrade almost 6 years
    Can I do this kind of thing without using <a> tag and window. Window is not available in all browsers and I do not want to create an <a> tag in my angular app.
  • Ixio
    Ixio over 5 years
    stackoverflow.com/a/52273870/2730032 works for me without needing the <a> trick used here and in the other answers. Is there a reason why it's not more upvoted and that this is still the top answer ?
  • kol
    kol over 5 years
    @Ixio Isn't msSaveOrOpenBlob Internet Explorer specific?
  • Ixio
    Ixio over 5 years
    @kol probably but I used the technique for other browsers: window.location = URL.createObjectURL(new File(...)) and it works fine for me on Firefox (I don't know about other browsers).
  • Konrad Höffner
    Konrad Höffner over 5 years
    For some reason, this fails for me when using Babel with Webpack, because the body element is not available yet, even if the code is only called after the document is loaded or not called at all. When using the untranspiled ES6 module source code, it works fine. I changed it to a normal function and declaring a reused a element outside of the function.
  • Russell Phillips
    Russell Phillips over 5 years
    I found that this setTimeout() hack fixes MS Edge, where the file would not download at all. However, only the call to revokeObjectURL() needs to be delayed.
  • Enrique Altuna
    Enrique Altuna over 5 years
    is there any way to open in it a new window?
  • Ram Babu
    Ram Babu over 5 years
    Thanks @ben. This is working fine. No dom elements, nothing like to trigger like click event. It just works awesome with proper extension. But the given file name is not considered, downloading "<object_url_id>.csv" instead of "<myfileName>.csv"
  • Fred
    Fred over 5 years
    Calling revokeObjectURL after location.assign works fine in Firefox, but breaks the download on Chrome.
  • Fred
    Fred over 5 years
    I think you can call link.click() instead of dispatching a mouse event.
  • Jacques Olivier
    Jacques Olivier over 5 years
    I found that the "if (window.navigator.msSaveOrOpenBlob)" is what did the trick for me
  • N8allan
    N8allan almost 5 years
    Worked perfectly.
  • beyond-code
    beyond-code almost 5 years
    Just to add, you don't need to actually mount the a tag to the body in order for this to work (tried just now in Chrome)
  • user1477388
    user1477388 over 4 years
    Note that "Edge does not support the File constructor." Ref. caniuse.com/#feat=fileapi
  • elahehab
    elahehab over 4 years
    I used the accepted solution but it didn't work at firefox! I still don't know why. Your solution worked in firefox. Thanks.
  • Luiz Felipe
    Luiz Felipe about 4 years
    This should be the correct answer. No point in creating useless objects in the DOM tree
  • Luiz Felipe
    Luiz Felipe about 4 years
    Now it does, since Jan '20
  • Manu Artero
    Manu Artero about 4 years
    As @RamBabuS says, this is not keeping fileName, but besides that works perfectly for me
  • junvar
    junvar about 4 years
    There is no need to call revokeObjectURL, the URL will automatically be revoked when the creating document (the page you were on) is closed. Which is also why you must use a new tab to view the file (at least in chrome).
  • F. Vosnim
    F. Vosnim almost 4 years
    Can I download a blob video with this function?
  • Gerros
    Gerros over 3 years
    The filename property works in firefox, but not in chrome... anyone a solution for chrome?
  • Experimenter
    Experimenter over 2 years
    The file name is not working in Chrome, so don't waste your time
  • LF00
    LF00 about 2 years
    How can I make works for the video tag with blob data.How to set the download file extension for blob data
  • Andrej Gaspar
    Andrej Gaspar about 2 years
    well done, thanks for help!
  • user210757
    user210757 about 2 years
    Why is saveData declared as an IIFE?
  • phil294
    phil294 almost 2 years
    weirdly enough, this adds auto file extensions when the filename is without one... I had some logfile called logfile and chrome made it logfile.xml without any indication from my side (it's not even an xml file)