Explain Codes LogoExplain Codes Logo

Force browser to download image files on click

javascript
download-attribute
feature-detection
cross-origin-images
Anton ShumikhinbyAnton Shumikhin·Dec 28, 2024
TLDR

Want to download an image on click? The download attribute is your best friend. Apply it to your anchor tag enclosing the image. href states your image's URL and download is your file's new name. For example:

<a href="image.jpg" download="cool_pic.jpg"> <img src="image.jpg" alt="An cool image"> </a>

Voila! Clicking the image prompts a download with the specified filename.

Dealing with compatibility and restrictions

Let's be brutally honest, not all browsers deal well with the download attribute. Some just wouldn't listen. Want to provide feedback or alternate instructions? Try using some feature detection action:

if ('download' in document.createElement('a')) { // If you're reading this, welcome to the download club! } else { // Sorry dear user, your browser didn't get the download memo. }

Having trouble with cross-origin images? Stuck because of some CORS policy? We've got a workaround. Download the image by setting the crossOrigin attribute to anonymous on an Image object, drawing to a canvas, and then sparking the download:

let img = new Image(); img.crossOrigin = "anonymous"; img.onload = function() { let canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; let ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); let dataURL = canvas.toDataURL('image/png'); let link = document.createElement('a'); link.href = dataURL; link.download = 'image.png'; link.click(); // Tada! Magic just happened! }; img.src = "cross-origin-image.jpg";

Programmatically triggering a download with JavaScript

What if you want to dynamically trigger downloads using JavaScript? Well, here's the good news, you can create an anchor element:

let link = document.createElement('a'); link.href = 'url/to/image.jpg'; // Change me! link.download = 'download_me.jpg'; // Change me too! document.body.appendChild(link); link.click(); document.body.removeChild(link); // A wild download has appeared!

Getting remote images and the fetch API

Want to grab images using the Fetch API? You can! Simply ensure to handle the response as a blob and use URL.createObjectURL():

fetch('url/to/image.jpg') // Just make sure to use the correct URL. 😜 .then(response => response.blob()) .then(blob => { let url = window.URL.createObjectURL(blob); let a = document.createElement('a'); a.href = url; a.download = 'filename.jpg'; document.body.appendChild(a); a.click(); a.remove(); // Your blobby image has been downloaded. Congrats! }) .catch(e => console.error(e));

Some extra toppings

When using the download attribute, it's quite handy to extract the file name from the URL or obtain the image's MIME type. This ensures that your file format is correct and consistent. After all, nobody wants to download a jpg file as .xlsx!

Handling Dynamic changes and consistency

For dynamically generated content or user actions, you might need to create a temporary element for the download initiation:

function pewpewDownload(imageUrl, filename) { let tmpLink = document.createElement('a'); tmpLink.href = imageUrl; tmpLink.setAttribute('download', filename); tmpLink.style.display = 'none'; document.body.appendChild(tmpLink); tmpLink.click(); document.body.removeChild(tmpLink); // Frameworks may come and go but creating elements on the fly never gets old! }

Keeping up with changing Browser Standards

Attaining consistency across browsers could be a Herculean task, thanks to recent Chrome deprecations and other browser updates. Staying informed about these changes ensures your download functionality remains in shipshape!