User-downloadable files face a significant UX problem: many have auto-generated, cryptic filenames that are difficult to read, and browsers often open linked files such as PDFs in a new tab, rather than downloading them. This is problematic: if you provide a button that says “Download X”, it’s reasonable to assume that the browser will download it, not open it.
Traditionally, these issues have been solved with complex server-side configuration and JavaScript foolery; today, you can use a little-known HTML5 attribute called download
to address both problems.
Using download with files
download
is simply added to a link: the attribute’s value is the new filename of the document for the user, including the extension. For example:
<a href="contract-856EF.pdf" download="Author Publishing Contract.pdf">
Author Contract
</a>
The same format can be used to link a button:
<a href="contract-856EF.pdf" download="Author Publishing Contract.pdf">
<button>Download Document</button>
</a>
There are a few limits: download
only works on pages delivered from a server: the code won’t work tested in a page on your desktop. Both Chrome and Firefox disable download
if the link points to a file on a domain different from the current one (the file can still be viewed and downloaded; it’s just the download
feature that is disabled).
Support and Feature Detection
Support for download
is excellent: all modern browsers - including the latest version of Microsoft Edge - support it, with the sole exception of Safari. download
is a nice example of HTML’s approach to progressive enhancement: if the browser doesn’t support the attribute, it will simply use the linked file’s filename, and view it appropriately. If you want to provide users with a little more guidance, feature detection is fairly straightforward:
var downloadSupported = ("download" in document.createElement("a"));
If downloadSupported
is false
, we can locate all the links with a download
attribute on the current page and modify them with a quick tip. To make the help and button text accurate, I’ll also detect the platform for a customized message:
function replaceWord(el) {
el.innerHTML = el.innerHTML
.replace("Download", "View")
}
var downloadSupported = ("download" in document.createElement("a"));
if (downloadSupported == false) {
var downloadLinks = document.querySelectorAll("a[download]"),
hintText = "",
ios = /iPad|iPhone|iPod/.test(navigator.platform),
mac = /MacIntel/.test(navigator.platform),
win = /Win32/.test(navigator.platform);
if (ios || mac || win ) {
if (win) { hintText = "Right-click"; }
if (mac) { hintText = "Control-click"; }
for (var i=0; i < downloadLinks.length; i++) {
replaceWord(downloadLinks[i]);
if ( mac || win ) {
downloadLinks[i].insertAdjacentHTML("afterend", "<div class="hint">"+hintText+" to download file</div>");
}
}
}
}
Modernizr also has a download
feature detection option, but if that’s the only feature you’re after, it’s better to write the script yourself.
Using download with other media
<canvas>
drawings can be saved from the browser, but only with a right / control-click… and the files always have the helpful name of download.png. We can use a link with the download
attribute to improve that:
<figure>
<a href="#" download="starfield.png">
<canvas id="starfield" width="800" height="400"></canvas>
</a>
<figcaption>Click to download image</figcaption>
</figure>
Alternatively, this could be written as a seperate link, with JavaScript added later in the page:
<canvas id="starfield" width="800" height="400"></canvas>
<a href="#" id="canvas-download">Download this image</a>
The JavaScript:
var starfield = document.getElementById("starfield"),
downloadLink = document.getElementById("canvas-download");
…
downloadLink.href = starfield.toDataURL();
downloadLink.download = "starfield.png";
download
can also be used with dataURI
encoded media, audio and video… essentially, any media the user has access to on your page.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.