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
    6 Things You Didn&#8217;t Know About Firefox OS

    Firefox OS is all over the tech news and for good reason:  Mozilla's finally given web developers the platform that they need to create apps the way they've been creating them for years -- with CSS, HTML, and JavaScript.  Firefox OS has been rapidly improving...

  • By
    Designing for Simplicity

    Before we get started, it's worth me spending a brief moment introducing myself to you. My name is Mark (or @integralist if Twitter happens to be your communication tool of choice) and I currently work for BBC News in London England as a principal engineer/tech...

Incredible Demos

  • By
    Create Your Own Dijit CSS Theme with LESS CSS

    The Dojo Toolkit seems to just get better and better.  One of the new additions in Dojo 1.6 was the use of LESS CSS to create Dijit themes.  The move to using LESS is a brilliant one because it makes creating your own Dijit theme...

  • By
    Create Spinning Rays with CSS3 Animations &#038; JavaScript

    Thomas Fuchs, creator of script2 (scriptaculous' second iteration) and Zepto.js (mobile JavaScript framework), creates outstanding animated elements with JavaScript.  He's a legend in his own right, and for good reason:  his work has helped to inspire developers everywhere to drop Flash and opt...

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!