JavaScript: export to CSV using the download attribute
March 17, 2014Last update: March 28, 2020
The problem
We have to allow our users to download data in CSV format.
A solution
Luckily, HTML5 provides a new download attribute for <a>
tag that tells to browsers to download linked resource rather than navigate to it.
Directly client side, we can prepare data and enable download without the need of the server. Of course, this is true if the browser supports the attribute. In case of missing support as fall back we have to rely on the server.
This is the code:
// some data to export
var data = [
{"title": "Book title 1", "author": "Name1 Surname1"},
{"title": "Book title 2", "author": "Name2 Surname2"},
{"title": "Book title 3", "author": "Name3 Surname3"},
{"title": "Book title 4", "author": "Name4 Surname4"}
];
// prepare CSV data
var csvData = new Array();
csvData.push('"Book title","Author"');
data.forEach(function(item, index, array) {
csvData.push('"' + item.title + '","' + item.author + '"');
});
// download stuff
var fileName = "data.csv";
var buffer = csvData.join("\n");
var blob = new Blob([buffer], {
"type": "text/csv;charset=utf8;"
});
var link = document.createElement("a");
if(link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
link.setAttribute("href", window.URL.createObjectURL(blob));
link.setAttribute("download", fileName);
}
else {
// it needs to implement server side export
link.setAttribute("href", "http://www.example.com/export");
}
link.innerHTML = "Export to CSV";
document.body.appendChild(link);
Along came IE. All front enders know that Microsoft does a lot of research to make their lives an hell, so let's see what he creates for us this time. IE 10+ doesn't support directly the download attribute, but we can mimic it.
We have to extend our code with this:
if(link.download !== undefined) { // feature detection
// Browsers that support HTML5 download attribute
...
}
else if(navigator.msSaveBlob) { // IE 10+
link.setAttribute("href", "#");
link.addEventListener("click", function(event) {
navigator.msSaveBlob(blob, fileName);
}, false);
}
else {
// it needs to implement server side export
...
}
In my honest opinion, I'll avoid to put proprietary code in scripts. The fall back that relies on the server is good to manage all old browsers or browsers that not support the attribute yet. I've write about this proprietary solution just to be thorough.
The complete example is available on GitHub.