'download attribute on <a> not working (NOT cross-domain)

Observe the following code:

let cv = document.createElement('canvas');
cv.toBlob(blob => {
    let a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = 'test.jpg';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
}, 'image/jpeg', 1);

If I open up the console on a new tab in my browser and paste this, it will download a file called test.jpg as expected. I have also done this on a variety of random websites (some on HTTPS, some on HTTP), and it worked everywhere. However, if I try this on my own website, Chrome will load the image in the tab instead of downloading it.

I am aware that the download attribute does not work with cross-domain URL's, but as you can see this is a blob: URL on the same domain. This behavior applies both to my test environment (which runs on localhost:8585) and my live website.

Now, I have read in the past that browsers sometimes treat localhost as cross-domain because it doesn't end in a valid TLD and therefore isn't a valid domain name (which would explain the bahvior on the test environment). My live website in turn has a .app TLD, which was introduced very recently -- so, the only explanation I can think of is that perhaps the browser doesn't yet recognize .app domains as valid, hence the cross-domain behavior.

Can anyone confirm my suspicion, or offer a solution?



Solution 1:[1]

I ran into the same issue, but it only affect my live site and not the development/localhost environment. I'm not able to figure out why, exactly, but it seems consistent across different browsers which makes me think something is getting configured differently somewhere.

However, I did find a solution by reviewing the code in download.js which worked for my site.

It seems the key is adding a stopPropagation() call in the anchor's click event.

Add this right before appending the new element to the document.body:

a.addEventListener('click', function(e) {
    e.stopPropagation();
    this.removeEventListener('click', arguments.callee);
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Matt