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
    I&#8217;m an Impostor

    This is the hardest thing I've ever had to write, much less admit to myself.  I've written resignation letters from jobs I've loved, I've ended relationships, I've failed at a host of tasks, and let myself down in my life.  All of those feelings were very...

  • By
    Convert XML to JSON with JavaScript

    If you follow me on Twitter, you know that I've been working on a super top secret mobile application using Appcelerator Titanium.  The experience has been great:  using JavaScript to create easy to write, easy to test, native mobile apps has been fun.  My...

Incredible Demos

  • By
    Drag and Drop MooTools File Uploads

    Honesty hour confession:  file uploading within the web browser sucks.  It just does.  Like the ugly SELECT element, the file input is almost unstylable and looks different on different platforms.  Add to those criticism the fact that we're all used to drag and drop operations...

  • By
    Save Web Form Content Using Control + S

    We've all used word processing applications like Microsoft Word and if there's one thing they've taught you it's that you need to save every few seconds in anticipation of the inevitable crash. WordPress has mimicked this functionality within their WYSIWYG editor and I use it...

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!