This isn't necessarily a new trick (and it's one I've covered sometime in the past), but I thought a quick example of how to do it in Vue.js would be helpful. For folks who may not know, HTML has included, for a few years now, a way to force a link to act as a download. This is done via the download attribute of the anchor tag. So for example:

<a href="cats.csv" download>Cats in CSV</a>

You can supply a filename to the download attribute but left blank like that it will use the filename specified in the link. While you can do this with "physical" files, you can also use it with JavaScript data on the client-side. There's multiple web pages explaining how to do this, but the general technique involves:

  • Creating an anchor element in JavaScript
  • Styling it to be invisible
  • Setting the link to a data URI that includes an encoded version of your data
  • Adding the element to the DOM
  • Firing the click event.
  • And then removing the element.

I found a nice example of this here: Making JavaScript download files without the server. Let's take this and add it to a simple Vue application.

First, let's begin with an app that just displays a table of cats. Not a cat on a table...

but an HTML table of cats. Here's the code with some static data:

const app = new Vue({
  el:'#app', 
  data: {
    cats:[
      {name:"Alese", gender:"female", age: 10},
      {name:"Sammy", gender:"male", age: 12},
      {name:"Luna", gender:"female", age: 8},
      {name:"Cracker", gender:"male", age: 7},
      {name:"Pig", gender:"female", age: 6},
      ]
  }
})

And here's the layout:

<div id="app" v-cloak>
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Gender</th>
        <th>Age</th>
      </tr>
    </thead>
    <tbody>
      
		<tr v-for="cat in cats">
        <td>{{cat.name}}</td>
        <td>{{cat.gender}}</td>
        <td>{{cat.age}}</td>
      </tr>
    
	</tbody>
  </table>
</div>

Now let's add a button to let the user download the information:

<p>
<button @click="download">Download</button>
</p>

And then a method to handle it:

download() {
	// credit: https://www.bitdegree.org/learn/javascript-download
	let text = JSON.stringify(this.cats);
	let filename = 'cats.json';
	let element = document.createElement('a');
	element.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(text));
	element.setAttribute('download', filename);

	element.style.display = 'none';
	document.body.appendChild(element);

	element.click();
	document.body.removeChild(element);     
}

For the most part this follows the blog post I linked to above with a few small changes. I modified the MIME type to be appropriate for JSON and switched a few var statements to let, because I'm hip like that. This works great and you can test it below:

See the Pen Vue Download by Raymond Camden (@cfjedimaster) on CodePen.

Cool. While this is nice, JSON is only really familiar to us nerds. It's a table of data, and tables just scream Excel, right? I've been enjoying the heck out of PapaParse lately for parsing CSV, but it also generates CSV as well. I added the library to my CodePen, and then spent about 30 seconds rewriting the code to support CSV:

download() {
	// credit: https://www.bitdegree.org/learn/javascript-download
	let filename = 'cats.csv';
	let text = Papa.unparse(this.cats);
	
	let element = document.createElement('a');
	element.setAttribute('href', 'data:text/csv;charset=utf-8,' + encodeURIComponent(text));
	element.setAttribute('download', filename);

	element.style.display = 'none';
	document.body.appendChild(element);

	element.click();
	document.body.removeChild(element); 
	
}

The changes were me just making use of the unparse method and then updating the filename and MIME type. That's literally it. Now if you download, and you have Excel or another such program installed, you can open up the file right away.

Excel in dark mode is so awesome. This is a picture of Excel rendering the cat data.

You can play with this version here:

See the Pen Vue Download 2 by Raymond Camden (@cfjedimaster) on CodePen.

Enjoy, and let me know if you've used this technique in your own code by leaving me a comment below!

Photo by Valentin Vlasov on Unsplash