Download File Using JavaScript/jQuery

1,448,009

Solution 1

Use an invisible <iframe>:

<iframe id="my_iframe" style="display:none;"></iframe>
<script>
function Download(url) {
    document.getElementById('my_iframe').src = url;
};
</script>

To force the browser to download a file it would otherwise be capable of rendering (such as HTML or text files), you need the server to set the file's MIME Type to a nonsensical value, such as application/x-please-download-me or alternatively application/octet-stream, which is used for arbitrary binary data.

If you only want to open it in a new tab, the only way to do this is for the user to a click on a link with its target attribute set to _blank.

In jQuery:

$('a#someID').attr({target: '_blank', 
                    href  : 'http://localhost/directory/file.pdf'});

Whenever that link is clicked, it will download the file in a new tab/window.

Solution 2

2019 modern browsers update

This is the approach I'd now recommend with a few caveats:

  • A relatively modern browser is required
  • If the file is expected to be very large you should likely do something similar to the original approach (iframe and cookie) because some of the below operations could likely consume system memory at least as large as the file being downloaded and/or other interesting CPU side effects.

fetch('https://jsonplaceholder.typicode.com/todos/1')
  .then(resp => resp.blob())
  .then(blob => {
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    // the filename you want
    a.download = 'todo-1.json';
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
    alert('your file has downloaded!'); // or you know, something with better UX...
  })
  .catch(() => alert('oh no!'));

2012 original jQuery/iframe/cookie based approach

I have created the jQuery File Download plugin (Demo) (GitHub) which could also help with your situation. It works pretty similarly with an iframe but has some cool features that I have found quite handy:

  • Very easy to setup with nice visuals (jQuery UI Dialog, but not required), everything is tested too

  • User never leaves the same page they initiated a file download from. This feature is becoming crucial for modern web applications

  • successCallback and failCallback functions allow for you to be explicit about what the user sees in either situation

  • In conjunction with jQuery UI a developer can easily show a modal telling the user that a file download is occurring, disband the modal after the download starts or even inform the user in a friendly manner that an error has occurred. See the Demo for an example of this. Hope this helps someone!

Here is a simple use case demo using the plugin source with promises. The demo page includes many other, 'better UX' examples as well.

$.fileDownload('some/file.pdf')
    .done(function () { alert('File download a success!'); })
    .fail(function () { alert('File download failed!'); });

Solution 3

function downloadURI(uri, name) 
{
    var link = document.createElement("a");
    // If you don't know the name or want to use
    // the webserver default set name = ''
    link.setAttribute('download', name);
    link.href = uri;
    document.body.appendChild(link);
    link.click();
    link.remove();
}

Check if your target browser(s) will run the above snippet smoothly:
http://caniuse.com/#feat=download

Solution 4

I'm surprised not a lot of people know about the download attribute for a elements. Please help spread the word about it! You can have a hidden html link, and fake a click on it. If the html link has the download attribute it downloads the file, not views it, no matter what. Here's the code. It will download a cat picture if it can find it.

document.getElementById('download').click();
<a href="https://docs.google.com/uc?id=0B0jH18Lft7ypSmRjdWg1c082Y2M" download id="download" hidden></a>

Note: This is not supported on all browsers: http://www.w3schools.com/tags/att_a_download.asp

Solution 5

I recommend using the download attribute for download instead of jQuery:

<a href="your_link" download> file_name </a>

This will download your file, without opening it.

Share:
1,448,009
Mithun Sreedharan
Author by

Mithun Sreedharan

Tweets @mithunp Works @QBurst

Updated on February 04, 2022

Comments

  • Mithun Sreedharan
    Mithun Sreedharan about 2 years

    I have a very similar requirement specified here.

    I need to have the user's browser start a download manually when $('a#someID').click();

    But I cannot use the window.href method, since it replaces the current page contents with the file you're trying to download.

    Instead I want to open the download in new window/tab. How is this possible?

  • Mithun Sreedharan
    Mithun Sreedharan over 13 years
    This method is not showing the download prompt, instead it embedded the pdf file at the end of the page. Please see my comments in letronje's answer
  • Randy the Dev
    Randy the Dev over 13 years
    A webpage cannot open a new tab automatically. To force the browser to download, get the server to send the pdf file with a nonsense MIME-type, such as application/x-please-download-me
  • Naftuli Kay
    Naftuli Kay over 12 years
    If I can't set the MIME type (it's not my server) is there any other way I can force downloads? I'm simply trying to hack a little jQuery together to download all MP3 files listed on a page to save myself time and pain.
  • Akrikos
    Akrikos over 11 years
    Nicely done! Solves the problem well. However, you may want to use: iframe.style.display = 'none'; as this will completely hide the iframe. Your current implementation will make the iframe invisible, but the iframe will still take up space at bottom of the page causing extra white space.
  • corbacho
    corbacho over 11 years
    FYI, Someone suggested (via editing my post) to add $idown.attr('src', url); after creating the iframe for the first time. I dont' think is needed. It's already setting the 'src:url' in the creation step.
  • corbacho
    corbacho over 11 years
    Also to comment that finally I didn't use this solution because IE 9 didn't like dynamically-created iframes pointing to http:// when you are inside a https web. I had to used "window.location.href", a solution that has some inconveniences too
  • Sagi Mann
    Sagi Mann over 11 years
    It "semi" works for me. I created the following simple test html: <html><body><iframe src="fileurl"></iframe></body></html> and it does get downloaded, but in the chrome console I see that the download was "canceled" and appears in red. This is part of a larger mobile web app, and the fact that it gets canceled breaks the app because it raises a general web failure. Any way around this?
  • nessur
    nessur over 11 years
    the "if($idown)" part didn't work for me in the latest Chrome(24), but just creating an endless number of iframes did. Maybe because I wanted to download 12 things at the same time?
  • rixo
    rixo over 10 years
    Nice snippet. However, setting a nonsensical things type is a bit disturbing. To ask the browser to download a file it can render, use the following header: Content-Disposition: attachment; filename="downloaded.pdf" (you can of course customize the filename as you need).
  • iOnline247
    iOnline247 over 10 years
    The if statement really should be: if( $idown && $idown.length > 0 )
  • jjxtra
    jjxtra almost 10 years
    Does not do anything in Chrome
  • davidkonrad
    davidkonrad about 9 years
    nice and simple solution for downloading textfiles, CSV's and so on +1, but does not seem to work with images.
  • Pacerier
    Pacerier about 9 years
    @AndrewDunn, What if the page has frames disabled due to X-Frame-Options header? (e.g. google.com)
  • Novellizator
    Novellizator about 9 years
    download filename didnt change... tested in chrome in april 2015
  • vllado2
    vllado2 almost 9 years
    Just tested it, in chrome, works perfect. Work with my file name and extension on download attribute.
  • g07kore
    g07kore almost 9 years
    For me this would be perfect but it doesn't not work on Firefox neither. Any idea?
  • Rodrigo Ruiz
    Rodrigo Ruiz over 8 years
    How do I force the download without a server? So just an html page with some javascript.
  • MatPag
    MatPag over 8 years
    Not supported in IE and Safari
  • Saran
    Saran over 8 years
    Chrome downloads, but Firefox just shows the picture.
  • Kunal Kakkad
    Kunal Kakkad over 8 years
    It will only support Chrome, Firefox, Opera and IE (>= 13.0 )
  • David
    David about 8 years
    Edge >= 13, not IE. Also the Edge 13 implementations is buggy because the name of the file is ignored and instead you get a file with an id as the name.
  • crabCRUSHERclamCOLLECTOR
    crabCRUSHERclamCOLLECTOR about 8 years
    In my opinion, this is the correct answer to the question. The other answers make sense if you have to support older browsers and need a workaround.
  • Bobort
    Bobort almost 7 years
    This does not work if your filePath has a querystring since submitting a form will overwrite the querystring in the action attribute.
  • Doopy
    Doopy over 6 years
    +1 for providing that executable snippet though. Saved me the time to test it only to find out it won't work.
  • Harald Hoerwick
    Harald Hoerwick about 6 years
    I workarrounded this by adding an input to the form: var authInput = $("<input>").attr("type", "hidden").attr("name", "myQsKey").val('MyQsValue'); $('<form></form>') .attr('action', filePath) .append($(authInput)) .appendTo('body').submit().remove(); This is equivalent acessing: filepath?myQsKey=myValue
  • Johnie Karr
    Johnie Karr almost 6 years
    This also works if you don't append the link to the DOM.
  • jean-baptiste
    jean-baptiste almost 6 years
    As mentioned in caniuse.com/#feat=download, this only works for same-origin links on recent Firefox and Chrome releases. So if your links points to another domain, it hardly works anywhere for now.
  • Okku
    Okku almost 6 years
    For it to work on Firefox, do document.body.appendChild(link) before the click and after the click you can do link.remove() to avoid polluting the DOM.
  • Okku
    Okku almost 6 years
    You can also do link.download = "" to have it retain its original file name and to avoid having to set one.
  • user1156544
    user1156544 over 5 years
    Latest Chrome (Aug 2018) shows picture too (because of an absurd security restriction) so fail
  • sudo rm -rf slash
    sudo rm -rf slash over 5 years
    Is it possible to detect when the download is completed using this method?
  • TRiG
    TRiG over 5 years
    Using a nonsense content-type is a terrible idea. The correct method, as @rixo said years ago, is Content-Disposition: attachment.
  • radu122
    radu122 over 5 years
    This also closes the websockets.
  • radu122
    radu122 over 5 years
    This is better than windows.location or <frame>, because it does not disconnect the websockets.
  • Ivo Smits
    Ivo Smits over 5 years
    This looks like a really complicated way to set window.location to filePath. Just window.location = filePath; would do the same.
  • Ashton Wiersdorf
    Ashton Wiersdorf over 5 years
    This creates a popup window, which most browsers block
  • Tigerware
    Tigerware over 4 years
    This is probably the easiest solution if you can set the contentType yourself. I use it as: window.location.href = downloadFileUrl;
  • Nearoo
    Nearoo over 4 years
    Chrome doesn't download for mp4s
  • Shrivaths Kulkarni
    Shrivaths Kulkarni over 4 years
    - I was trying this with pdf files. File is getting downloaded but its always corrupt. Any suggestions? Thank you
  • Mark Amery
    Mark Amery over 4 years
    Your modern example here doesn't seem to me to make a great deal of sense. Why would you download something from a real HTTPS URL via fetch, create a blob from it, create a blob URL from the blob, and then use an anchor with the download attribute to download from the blob URL, when you could instead just... use an anchor with the download attribute to download from the HTTPS URL you started with?
  • Mark Amery
    Mark Amery over 4 years
    Who's Andrew? Referring to users on Stack Overflow by name isn't too helpful, because they change names. I don't know whose work this answer was inspired by, now.
  • Mark Amery
    Mark Amery over 4 years
    Unless headers returned from the server indicate to do otherwise, this will simply navigate to url, not download from it.
  • Mark Amery
    Mark Amery over 4 years
    Regardless of whether there's a downside to this solution, per se, you haven't provided any upside to using this over a link. (And there is a downside: you can't use the download attribute this way to tell the browser that you want a download regardless of what headers the server returns, which you can do with an a element.)
  • Mark Amery
    Mark Amery over 4 years
    How is this an improvement? It appears to simply be a more complicated way of doing the same thing.
  • Mark Amery
    Mark Amery over 4 years
    This is just the same approach as shown in Imagine Breaker's answer years earlier, but with the added downside of requiring jQuery.
  • Mark Amery
    Mark Amery over 4 years
    What's the point of using MouseEvent here instead of always using click? And why append the link to the document before clicking it? Maybe this has advantages over the simpler approach shown in stackoverflow.com/a/23013574/1709587, but if so, they're not explained here.
  • Mark Amery
    Mark Amery over 4 years
    This... seems to just be for XHR, not file downloads? I don't see the relevance here.
  • Mark Amery
    Mark Amery over 4 years
    This whole function body is just an overcomplicated way of doing window.location.href = url. The link you create isn't used for anything.
  • John Culviner
    John Culviner over 4 years
    @MarkAmery that works too as other answers have indicated. That approach (AFAIK) doesn't give you feedback on when the download starts, when it completed and if it errored which is handy. I could add that to the answer for a "fire and forget" option. Also the [download] attribute doesn't allow for a POST or anything exotic either.
  • Abk
    Abk over 4 years
    It's been a while I posted this answer. I can't remember if there's any reason behind those unnecessary lines of code.
  • Sean
    Sean over 4 years
    caniuse shows support in Edge and Safari so seems like this should work unless you need to support IE or older versions of Safari. caniuse.com/#search=download
  • madsongr
    madsongr about 4 years
    Hi, is there a way to get a php response inside this <iframe>? I'm using your answer to send a url with params to a php file to download a zip file. I'm reading console.log(iframe) to find a "possible" response but could not find it until now
  • Naren Verma
    Naren Verma about 4 years
    If admin doesn't want to show the URL to the user than?
  • klodoma
    klodoma over 3 years
    Your modern example is not quite right. It will "download" whatever the server returns. For ex, if you have an authentication error, it will return the login page or whatever the server returns and not the "downloaded file" itself.
  • DevAB
    DevAB almost 3 years
    Where is the download code? You're just adding an iframe
  • Math Coder 101
    Math Coder 101 almost 3 years
    It shows the picture, but does not download it.
  • Aloti
    Aloti over 2 years
    when URL is for pdf or image files it opens anothers browser window and display the files but never download them!!!
  • Lying_cat
    Lying_cat over 2 years
    👍, this is useful and convenient.
  • Itamar Smirra
    Itamar Smirra over 2 years
    About your modern example, if you want to avoid adding this (let's be honest) not so nice code, there are several light-weight packages that can do this for you. My favorite is 'fs-browsers' - npmjs.com/package/fs-browsers.
  • y_159
    y_159 over 2 years
    But what if we need to pass payload with the link?
  • y_159
    y_159 over 2 years
    we can pass some request payload in the body section with the url? It'll be like hitting the url with a POST request. How do we pass a dictionary in this case?
  • y_159
    y_159 over 2 years
    How do we make this as a post request?
  • Itamar Smirra
    Itamar Smirra over 2 years
    Thats right, fs-browsers is not :)
  • Adam Sassano
    Adam Sassano almost 2 years
    If use a Data URI instead of a Blob URI, you can combine the downloader and downloadURI functions and write it in one line: const downloader = (data, mediaType, fileName) => Object.assign(document.createElement('a'), { href: `data:${mediaType}, ${encodeURIComponent(data)}`, download: fileName }).click();
  • Peter Moore
    Peter Moore almost 2 years
    Does the same-origin trollopotry here at least honor CORS headers?