Download File Using JavaScript/jQuery
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.
Comments
-
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 over 13 yearsThis 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 over 13 yearsA 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 over 12 yearsIf 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 over 11 yearsNicely 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 over 11 yearsFYI, 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 over 11 yearsAlso 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 over 11 yearsIt "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 over 11 yearsthe "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 over 10 yearsNice 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 over 10 yearsThe
if
statement really should be:if( $idown && $idown.length > 0 )
-
jjxtra almost 10 yearsDoes not do anything in Chrome
-
davidkonrad about 9 yearsnice and simple solution for downloading textfiles, CSV's and so on +1, but does not seem to work with images.
-
Pacerier about 9 years@AndrewDunn, What if the page has frames disabled due to
X-Frame-Options
header? (e.g. google.com) -
Novellizator about 9 yearsdownload filename didnt change... tested in chrome in april 2015
-
vllado2 almost 9 yearsJust tested it, in chrome, works perfect. Work with my file name and extension on download attribute.
-
g07kore almost 9 yearsFor me this would be perfect but it doesn't not work on Firefox neither. Any idea?
-
Rodrigo Ruiz over 8 yearsHow do I force the download without a server? So just an html page with some javascript.
-
MatPag over 8 yearsNot supported in IE and Safari
-
Saran over 8 yearsChrome downloads, but Firefox just shows the picture.
-
Kunal Kakkad over 8 yearsIt will only support Chrome, Firefox, Opera and IE (>= 13.0 )
-
David about 8 yearsEdge >= 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 about 8 yearsIn 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 almost 7 yearsThis does not work if your
filePath
has a querystring since submitting a form will overwrite the querystring in the action attribute. -
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 about 6 yearsI 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 almost 6 yearsThis also works if you don't append the link to the DOM.
-
jean-baptiste almost 6 yearsAs 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 almost 6 yearsFor it to work on Firefox, do
document.body.appendChild(link)
before the click and after the click you can dolink.remove()
to avoid polluting the DOM. -
Okku almost 6 yearsYou can also do
link.download = ""
to have it retain its original file name and to avoid having to set one. -
user1156544 over 5 yearsLatest Chrome (Aug 2018) shows picture too (because of an absurd security restriction) so fail
-
sudo rm -rf slash over 5 yearsIs it possible to detect when the download is completed using this method?
-
TRiG over 5 yearsUsing a nonsense content-type is a terrible idea. The correct method, as @rixo said years ago, is
Content-Disposition: attachment
. -
radu122 over 5 yearsThis also closes the websockets.
-
radu122 over 5 yearsThis is better than windows.location or <frame>, because it does not disconnect the websockets.
-
Ivo Smits over 5 yearsThis looks like a really complicated way to set
window.location
tofilePath
. Justwindow.location = filePath;
would do the same. -
Ashton Wiersdorf over 5 yearsThis creates a popup window, which most browsers block
-
Tigerware over 4 yearsThis is probably the easiest solution if you can set the contentType yourself. I use it as: window.location.href = downloadFileUrl;
-
Nearoo over 4 yearsChrome doesn't download for
mp4
s -
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 over 4 yearsYour 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 thedownload
attribute to download from the blob URL, when you could instead just... use an anchor with thedownload
attribute to download from the HTTPS URL you started with? -
Mark Amery over 4 yearsWho'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 over 4 yearsUnless headers returned from the server indicate to do otherwise, this will simply navigate to
url
, not download from it. -
Mark Amery over 4 yearsRegardless 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 ana
element.) -
Mark Amery over 4 yearsHow is this an improvement? It appears to simply be a more complicated way of doing the same thing.
-
Mark Amery over 4 yearsThis is just the same approach as shown in Imagine Breaker's answer years earlier, but with the added downside of requiring jQuery.
-
Mark Amery over 4 yearsWhat's the point of using
MouseEvent
here instead of always usingclick
? 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 over 4 yearsThis... seems to just be for XHR, not file downloads? I don't see the relevance here.
-
Mark Amery over 4 yearsThis 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 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 over 4 yearsIt's been a while I posted this answer. I can't remember if there's any reason behind those unnecessary lines of code.
-
Sean over 4 yearscaniuse 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 about 4 yearsHi, 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 readingconsole.log(iframe)
to find a "possible" response but could not find it until now -
Naren Verma about 4 yearsIf admin doesn't want to show the URL to the user than?
-
klodoma over 3 yearsYour 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 almost 3 yearsWhere is the download code? You're just adding an iframe
-
Math Coder 101 almost 3 yearsIt shows the picture, but does not download it.
-
Aloti over 2 yearswhen URL is for pdf or image files it opens anothers browser window and display the files but never download them!!!
-
Lying_cat over 2 years👍, this is useful and convenient.
-
Itamar Smirra over 2 yearsAbout 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 over 2 yearsBut what if we need to pass payload with the link?
-
y_159 over 2 yearswe 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 over 2 yearsHow do we make this as a post request?
-
Itamar Smirra over 2 yearsThats right, fs-browsers is not :)
-
Adam Sassano almost 2 yearsIf 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 almost 2 yearsDoes the same-origin trollopotry here at least honor CORS headers?