18

<a download='file' href="https://tinyjpg.com/images/social/website.jpg">
  Download
</a>

Is there a way to force the download of a file instead of opening the file in a new window? Right now if the file is a URL, like the example below it won't be downloaded and will open in a new window.

cigien
  • 57,834
  • 11
  • 73
  • 112
gnifrus
  • 243
  • 1
  • 2
  • 6

5 Answers5

39

You may be bitten by the fact that Firefox and Chrome 65+ only support same-origin download links, probably as a security measure.

Source: https://caniuse.com/#feat=download (see "Known issues" tab)

The Web Hypertext Application Technology Working Group (WHATWG) recommends that in cross-origin scenarios (as in your example), the web server that is hosting the image/file in question needs to send a Content-Disposition HTTP header for download= to be honored.

Source: https://html.spec.whatwg.org/multipage/links.html#downloading-resources


In short:

You can only use <a download='...'></a> to force download of an image/file, if:

  1. the html and the image/file are both being hosted on the same domain,
    or
  2. the html and the image/file are on different domains, and the external image/file server also says it should be downloaded by means of a Content-Disposition HTTP header.
Peter B
  • 22,460
  • 5
  • 32
  • 69
2

Maybe you have solved in the meanwhile, but since you are hosting the files on S3 (see comments on Peter B's answer), you need to add a signature to the files url and set the ResponseContentType to binary/octet-stream by using the aws sdk. I am using Node so it becomes:

const promises = array.map((item) => {
        const promise = s3.getSignedUrlPromise('getObject', {
            Bucket: process.env.S3_BUCKET,
            Key: key, //filename
            Expires: 604800, //time to expire in seconds (optional)
            ResponseContentType: 'binary/octet-stream' 
        });

        return promise;
    });

    const links = await Promise.all(promises);

I hope this helps.

Mattia Rasulo
  • 1,236
  • 10
  • 15
0

setTimeout(function() {
  
   url = 'https://media.sproutsocial.com/uploads/2017/02/10x-featured-social-media-image-size.png';
   // downloadFile(url); // UNCOMMENT THIS LINE TO MAKE IT WORK
  
}, 2000);

// Source: http://pixelscommander.com/en/javascript/javascript-file-download-ignore-content-type/
window.downloadFile = function (sUrl) {

    //iOS devices do not support downloading. We have to inform user about this.
    if (/(iP)/g.test(navigator.userAgent)) {
       //alert('Your device does not support files downloading. Please try again in desktop browser.');
       window.open(sUrl, '_blank');
       return false;
    }

    //If in Chrome or Safari - download via virtual link click
    if (window.downloadFile.isChrome || window.downloadFile.isSafari) {
        //Creating new link node.
        var link = document.createElement('a');
        link.href = sUrl;
        link.setAttribute('target','_blank');

        if (link.download !== undefined) {
            //Set HTML5 download attribute. This will prevent file from opening if supported.
            var fileName = sUrl.substring(sUrl.lastIndexOf('/') + 1, sUrl.length);
            link.download = fileName;
        }

        //Dispatching click event.
        if (document.createEvent) {
            var e = document.createEvent('MouseEvents');
            e.initEvent('click', true, true);
            link.dispatchEvent(e);
            return true;
        }
    }

    // Force file download (whether supported by server).
    if (sUrl.indexOf('?') === -1) {
        sUrl += '?download';
    }

    window.open(sUrl, '_blank');
    return true;
}

window.downloadFile.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
window.downloadFile.isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;
0

You can use this function to downlaod images using fetch

async function downloadImage(imageSrc) {
  const image = await fetch(imageSrc)
  const imageBlog = await image.blob()
  const imageURL = URL.createObjectURL(imageBlog)

  const link = document.createElement('a')
  link.href = imageURL
  link.download = 'image file name here'
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}
-8

Your link should have an ID to force download:

<a download='website.jpg' id='blablabla' href="https://tinyjpg.com/images/social/website.jpg">
  Download
</a>