Force Download with JavaScript

By  on  

Force download scripts have been an important part of internet usability for a long time.  I can attest to that by the number of times I've implemented this feature on the server side and the popularity of my PHP Force Download post, even to this day.  With the web world having moved much more the client side, I started looking for a method to force download without the need of a server, and I found it....right in the Firefox DevTools Debugger!

The JavaScript

The function to do this is quite small and relies on URL.createObjectUrl:

function downloadFile(data, fileName, type="text/plain") {
  // Create an invisible A element
  const a = document.createElement("a");
  a.style.display = "none";
  document.body.appendChild(a);

  // Set the HREF to a Blob representation of the data to be downloaded
  a.href = window.URL.createObjectURL(
    new Blob([data], { type })
  );

  // Use download attribute to set set desired file name
  a.setAttribute("download", fileName);

  // Trigger the download by simulating click
  a.click();

  // Cleanup
  window.URL.revokeObjectURL(a.href);
  document.body.removeChild(a);
}

The function injects an <a> element into the body, sets it URL to a Blob value to the text content of the destination file, and clicks the element to trigger the download.  The element remains hidden during the process and is removed from the DOM immediately after the click() call.  As soon as the function is called, the browser's download prompt is displayed.

I look forward to learning more about both createObjectURL and Blob; those two are the true magic of this technique!

Shout out to Sneha Jain for implementing this great technique within the Firefox DevTools debugger!

Recent Features

  • By
    Create a CSS Flipping Animation

    CSS animations are a lot of fun; the beauty of them is that through many simple properties, you can create anything from an elegant fade in to a WTF-Pixar-would-be-proud effect. One CSS effect somewhere in between is the CSS flip effect, whereby there's...

  • By
    How to Create a RetroPie on Raspberry Pi &#8211; Graphical Guide

    Today we get to play amazing games on our super powered game consoles, PCs, VR headsets, and even mobile devices.  While I enjoy playing new games these days, I do long for the retro gaming systems I had when I was a kid: the original Nintendo...

Incredible Demos

  • By
    Introducing MooTools Dotter

    It's best practice to provide an indicator of some sort when performing an AJAX request or processing that takes place in the background. Since the dawn of AJAX, we've been using colorful spinners and imagery as indicators. While I enjoy those images, I am...

  • By
    Web Notifications API

    Every UI framework has the same set of widgets which have become almost essential to modern sites: modals, tooltips, button varieties, and notifications.  One problem I find is each site having their own widget colors, styles, and more -- users don't get a consistent experience.  Apparently the...

Discussion

  1. Pauli Sudarshan Terho

    Typo {type} should be replaced by {type: type}. Ex: {type: "text/plain;charset=utf-8"}

    • { type } is acting exactly like { type : type}

  2. Bronius

    Quite nice and concise. This works with generating a text file and downloading it: What’s the magic to fetch a remote text file not even on my server and handing it back to the browser for download? I want to avoid streaming through php.. In my case they are small enough that maybe I could stream thru js?

    • Bronius

      Ah ha! It is possible! Preceding Dave Walsh’s script above, I first stream a fetch of the file (remote or “local” on the server) with fetch() like:

              let blob = await fetch(uri).then(r => r.blob());
              let fileContents = await (new Response(blob)).text();
      

      Then I pass fileContents into the function in this solution as data. I don’t know if this is the best way, but it seems to be working great in my testing.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!