Another one of those 'born of an issue I stumbled across' sort of situations, I came across the need to save some data entered into a form (some configuration details into a textarea to be specific).

Sure, there are lots of means available to save something to the local machine of a user, but they tend to involve either less-than-ideal solutions such as a browser's local storage, a cookie, or even using the HTML canvas blob.

The need for simple solutions

There is a great article (if not a little out of date by now) by Eli Grey on saving generated files on the client side that also discusses his excellent utility FileSaver.js, which utilises the very same canvas blob functions mentioned above.

However, for me, it seemed a little overblown to bring in another utility dependency to perform a really simple task of creating a small text file and stashing it on the client's machine.

A vanilla JS solution to client-side file saving

So here we are, a really simple way to create and save a file on the client side, from the browser, based on some information saved into a textarea.

First, the HTML...

<fieldset>
  <legend>Enter some config details</legend>
  <textarea></textarea>
  <button id="btnSave">save config</button>
</fieldset>

Which renders the following no-frills elements in the browser (styling not shown for simplicity):

Screenshot of the textarea and save button ready to save the file

Now, for the JavaScript:

const downloadToFile = (content, filename, contentType) => {
  const a = document.createElement('a');
  const file = new Blob([content], { type: contentType });

  a.href = URL.createObjectURL(file);
  a.download = filename;
  a.click();

  URL.revokeObjectURL(a.href);
};

document.querySelector('#btnSave').addEventListener('click', () => {
  const textArea = document.querySelector('textarea');

  downloadToFile(textArea.value, 'my-new-file.txt', 'text/plain');
});

What we've got going on here, is a plain, browser-native querySelector call that grabs our button with the id btnSave, attaches an event listener that fires on click β€” nothing too fancy here.

Where the magic (well, really simple magic) is in the 'downloadToFile' method above. We create a new anchor element and a new Blob object using the content and contentType arguments we passed in.

Next, we set the href element to the result of the URL.createObjectURL() method that creates a DOMString containing a URL that represents the file object we just made.

Finally, we trigger our new anchor element's click event, which kicks off the download process in the browser, before cleaning things up using the URL.revokeObjectURL() method.

See it in action

You can view the code in action in my CodePen, or below in a handy iFrame.

Wrapping things up

And that's it. Nice and simple, gets the job done. Sometimes, the most straightforward solution is the best one if you need something lightweight that just works.

You might also like these articles that use plain old JS and CSS: