JavaScript provides built-in methods and properties to download files on the client-side without requiring server interaction. This comprehensive guide demonstrates multiple techniques to download various file types using plain JavaScript.

Introduction

The ability to trigger file downloads is an essential feature in most web applications. For example, you may allow users to download documents, reports, or other digital content generated on your site.

Traditionally, forcing a file download required configuring the server to send specific header responses. However, modern browsers now support client-side file generation and downloading using JavaScript and the HTML5 blob and URL.createObjectURL() features.

In this post, you will learn:

  • The difference between downloading files from a server vs. client-side generation
  • Multiple methods to trigger downloads including:
    • Anchor tags
    • Programmatically creating and clicking anchor elements
    • Using the download attribute
    • Creating and revoking Object URLs
    • Generating Files from Data URLs
  • How to download multiple file types like PDFs, Excel sheets, plain text, JSON, images etc.
  • Techniques for customizing downloaded file properties like names

So let‘s get started!

Downloading Server Files vs. Client-Side Generation

Before we dive into the code, it‘s important to understand the key difference between downloading a file stored on a server vs. using JavaScript to generate one.

Downloading Existing Files

The most straightforward approach is to link directly to a file stored on your server or another website. For example:

<a href="path/to/file.pdf" download>Download PDF</a> 

Here the href points to the file location causing the browser to fetch and prompt the user to download it. This approach downloads the file as-is without any client-side generation.

While simple, the disadvantage is that you can only download static files stored on a publicly accessible server.

Client-Side File Generation

Modern browsers support dynamically generating files using JavaScript that you can trigger the client to download.

For example, you can programmatically build Excel sheets, zip archives, PDFs and more using just client-side JavaScript without needing server coordination.

The advantage of this approach is you can create files on demand instead of requiring them to be pre-built. The tradeoff is it requires more JavaScript to construct the file contents compared to just directly linking.

Now that we understand the high-level difference between the approaches, let‘s explore some code examples.

File Download Methods

There are a few common techniques for triggering browser file downloads in JavaScript:

1. Anchor Tag

You can use an anchor tag with download attribute to initiate a file download:

const anchor = document.createElement(‘a‘);
anchor.href = fileData; // Link to file data
anchor.download = ‘my-file.txt‘; // Filename 
anchor.click();

This programmatically generates an <a> tag pointing to the file content that when clicked prompts the download dialog box.

Run Code Example

2. Revoking Object URL

The URL.createObjectURL() method generates a temporary internal URL representing file data.

You can trigger a download by creating an object URL then revoking it:

const fileUrl = URL.createObjectURL(fileData); 

// Trigger download
const link = document.createElement(‘a‘);
link.href = fileUrl;  
link.download = ‘my-file.txt‘;
document.body.appendChild(link);
link.click(); 

// Revoke object URL
URL.revokeObjectURL(fileUrl);  

This approach avoids unnecessarily storing data in the session history.

Run Code Example

3. Data URL

You can use a Data URL which embeds file data directly into the source string with a data: prefix:

const dataStr = "data:text/plain;charset=utf-8," + encodeURIComponent(fileData);

const link = document.createElement(‘a‘);
link.href = dataStr;
link.download = ‘my-file.txt‘; 

document.body.appendChild(link);
link.click(); 
document.body.removeChild(link); 

The benefit of data URLs is they contain all information required to recreate the file without external requests.

Run Code Example

Now let‘s look at applying these techniques for common download use cases.

Use Case 1: Download Text Files

A common example is allowing users to download plain text documents like CSVs, JSON data, log contents etc.

Here‘s an example function to download text:

function downloadText(text, filename) {

  const blob = new Blob([text], { type: ‘text/plain‘ });

  const link = document.createElement(‘a‘);
  link.download = filename;
  link.href = URL.createObjectURL(blob);
  link.onclick = destroyClickedLink;

  document.body.appendChild(link);
  link.click();
}

function destroyClickedLink(event) {
  document.body.removeChild(event.target);
}

We create a blob containing the raw text, generate an object URL representing it, create a dummy link element in the DOM that when clicked triggers the download, then tidies up the node.

Let‘s test it out:

const fileContents = ‘Hello world!‘;
downloadText(fileContents, ‘example.txt‘);

This allows downloading arbitrary text client-side without needing a server endpoint.

Run Code Example

The same approach works great for data formats like CSV, JSON, XML and plain text.

Use Case 2: Generate and Download PDF Files

Generating PDF files requires more effort since you need to construct a full document object.

Here‘s an example using the jsPDF library:

import jsPDF from ‘jspdf‘;

function generatePDF() {

  const doc = new jsPDF();

  doc.text(‘Hello world!‘, 10, 10);

  const pdfBlob = new Blob([doc.output()], {type: ‘application/pdf‘});

  const link = document.createElement(‘a‘);
  link.href = URL.createObjectURL(pdfBlob);
  link.download = ‘example.pdf‘;

  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);

}

generatePDF();  

We use jsPDF to programmatically generate the PDF by adding text, images etc. then output as a Blob which we can trigger the client to download.

There are a variety of client-side PDF generators like PDFKit, PdfMake and more that open lots of possibilities for on-demand file generation.

Run Code Example

Use Case 3: Download Excel Files

Similarly, you can leverage libraries like SheetJS to generate Excel spreadsheets and trigger downloads:

import * as XLSX from ‘xlsx‘;

function generateExcel() {

  const workbook = XLSX.utils.book_new();

  const worksheet = XLSX.utils.aoa_to_sheet([
    [‘Value 1‘, ‘Value 2‘],
    [1, 2] 
  ]);

  XLSX.utils.book_append_sheet(workbook, worksheet, ‘Sheet1‘);

  const workbookBlob = new Blob([XLSX.write(workbook, {type:‘application/vnd.ms-excel‘})], {type: ‘application/vnd.ms-excel‘});

  const link = document.createElement(‘a‘);
  link.download = ‘example.xlsx‘;
  link.href = URL.createObjectURL(workbookBlob);
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link); 
}

generateExcel();

Here we use the SheetJS library to build an Excel workbook from scratch including the cell data then trigger the client-side download.

Run Code Example

This opens the door to creative on-demand Excel generation solutions on the front end.

Use Case 4: Download Images

Downloading images using JavaScript involves converting them into Blob URLs.

Let‘s implement a function to accept an <img> element and trigger the user to download it:

function downloadImage(imageElement, filename) {

  fetch(imageElement.src) 
    .then(res => res.blob())
    .then(blob => {

      const link = document.createElement(‘a‘);
      link.download = filename;  
      link.href = URL.createObjectURL(blob);
      document.body.appendChild(link);
      link.onclick = () => {
        document.body.removeChild(link); 
        window.URL.revokeObjectURL(link.href);  
      }

      link.click();
    });

}

Here we fetch the image data then extract as a Blob which creates an object URL for us to create an <a> tag linking to.

When the link is clicked to trigger the download we tidy up by revoking the object URL afterwards.

Let‘s test it:

const img = document.getElementById(‘my-image‘);
downloadImage(img, ‘example.jpg‘);

This approach works great for letting users download images already loaded on the page.

Run Code Example

Customizing Downloads

There‘s a few ways we can customize properties of files downloaded with JavaScript:

Filename

By default, browsers will use the response filename or generate one automatically like "download".

You can specify custom filenames using link.download:

link.download = ‘report-12345.pdf‘;

File Type

When constructing Blobs, you can specify the MIME content type:

const pdfBlob = new Blob([data], {type: ‘application/pdf‘});

This helps signal to the browser the format of the file.

File Size

Dynamically generated files may have small byte sizes that confuse some native applications expecting larger documents.

To address, you can attach padding data:

const contentPadding = ‘ ‘.repeat(10000);
const blob = new Blob([content + contentPadding]); 

This expands the file to a reasonable minimum size.

Save vs. Open

Browsers will prompt whether to "Save As…" or open generated files immediately.

Use the link.download attribute to encourage save vs. open dialog:

<a href="file.zip" download="archive.zip">Download</a>

Compatibility Fallbacks

Most modern browsers now have excellent support for client-side file generation and downloading using JavaScript.

However, you may still wish to handle legacy browser fallbacks:

function downloadFile(fileData, filename) {

  if (window.navigator.msSaveOrOpenBlob) {

    // IE workaround
    window.navigator.msSaveOrOpenBlob(fileData, filename);
    return;

  } 

  // Modern browser flow...

  const blob = new Blob([fileData]);
  const url = URL.createObjectURL(blob);

  // ...trigger download

}

This provides a backup IE-compatible path using msSaveOrOpenBlob.

You can also detect support individual features like Blob or the download attribute to selectively handle legacy browsers.

Other Examples

Here‘s a few more examples of downloading common file types:

Zip Archives

// Zip multiple files
const zip = new JSZip();
zip.file(‘file1.txt‘, fileData1);
zip.file(‘file2.txt‘, fileData2);

const zipBlob = await zip.generateAsync({type:"blob"});

downloadBlob(zipBlob, ‘archive.zip‘);

JSON Data

const jsonData = {
  name: ‘John‘  
};

downloadText(JSON.stringify(jsonData), ‘data.json‘);  

CSV Contents

const csvData = [
  [‘Name‘, ‘Age‘],
  [‘John‘, 30]
];

downloadCsv(Papa.unparse(csvData), ‘data.csv‘);

Conclusion

JavaScript provides everything you need to implement powerful file downloading without depending on server-side code.

Key takeaways:

  • Leverage blob & ObjectURL to generate files that trigger downloads
  • Support many formats: text, JSON, CSV, PDF, Excel, zip archives etc.
  • Customize filenames, types and sizes
  • Polyfill legacy browser support with fallbacks

Client-side downloading opens lots of possibilities like allowing users to export data from your web app into reusable formats.

To learn more, check out these tutorials:

Hopefully this gives you a comprehensive foundation for implementing robust file download capabilities using plain JavaScript!

Similar Posts