FileSaver.js - Documentation

Introduction

What is FileSaver.js?

FileSaver.js is a JavaScript library that allows you to save files on the client-side, directly from the user’s web browser. It provides a simple and consistent API for saving files of various types, bypassing the browser’s often inconsistent and limited native file download mechanisms. This means you can programmatically trigger a file download without relying on <a> tags or form submissions.

Why use FileSaver.js?

Browser Compatibility

FileSaver.js supports a wide range of modern browsers, including:

For older browsers that lack the necessary features, FileSaver.js gracefully degrades, often using a fallback mechanism to provide the functionality. Check the official repository for the most up-to-date compatibility information. It’s generally compatible with any browser that supports Blob objects.

Installation

FileSaver.js can be easily installed using various methods:

Basic Usage

Saving a simple text file

The simplest way to use FileSaver.js is to save a plain text file. This example saves a text string as a .txt file:

import { saveAs } from 'file-saver';

const textToSave = 'Hello, FileSaver.js!';
const blob = new Blob([textToSave], { type: 'text/plain;charset=utf-8' });
saveAs(blob, 'my-file.txt');

This code first creates a Blob object from the text string, specifying the MIME type as text/plain. Then, it uses the saveAs function to initiate the download, providing the Blob and the desired filename.

Saving a Blob object

FileSaver.js primarily works with Blob objects. A Blob represents a file-like object in the browser. You can create a Blob from various data sources, including strings, arrays, and array buffers. This example demonstrates saving a Blob created from an array of strings:

import { saveAs } from 'file-saver';

const data = [
  'Line 1',
  'Line 2',
  'Line 3'
];
const blob = new Blob(data, { type: 'text/plain;charset=utf-8' });
saveAs(blob, 'my-data.txt');

Remember to specify the appropriate MIME type based on the content of your Blob.

Specifying the filename

The second argument to the saveAs function determines the filename. You can use any valid filename, including extensions:

import { saveAs } from 'file-saver';

const blob = new Blob(['This is my file content.'], { type: 'text/plain;charset=utf-8' });
saveAs(blob, 'my-document.txt'); //Saves as my-document.txt

The filename should include the desired extension to indicate the file type to the user’s operating system.

Setting file type and extensions

The file type is crucial and is set using the type property within the Blob constructor. This determines how the browser handles the downloaded file (e.g., which application opens it). The filename extension should generally correspond to the MIME type.

import { saveAs } from 'file-saver';

//Save a CSV file
const csvData = 'Name,Age,City\nJohn,30,New York\nJane,25,London';
const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8' });
saveAs(blob, 'my-data.csv');


// Save a JSON file
const jsonData = JSON.stringify({ name: 'John Doe', age: 30 });
const jsonBlob = new Blob([jsonData], { type: 'application/json;charset=utf-8' });
saveAs(jsonBlob, 'data.json');

Incorrect MIME types can lead to the file not opening correctly or being handled unexpectedly by the browser. Make sure to use the correct MIME type for the data you’re saving.

Advanced Usage

Saving data URLs

You can save files from data URLs using FileSaver.js. First, you need to convert the data URL into a Blob:

import { saveAs } from 'file-saver';

function dataURLtoBlob(dataurl) {
  let arr = dataurl.split(','),
      mime = arr[0].match(/:(.*?);/)[1],
      bstr = atob(arr[1]),
      n = bstr.length,
      u8arr = new Uint8Array(n);

  while(n--){
    u8arr[n] = bstr.charCodeAt(n);
  }

  return new Blob([u8arr], {type:mime});
}


const dataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const blob = dataURLtoBlob(dataUrl);
saveAs(blob, 'image-from-dataurl.png');

This example defines a helper function dataURLtoBlob to perform the conversion before passing the resulting Blob to saveAs.

Saving from a canvas element

To save the contents of a canvas element, you first need to get the image data as a data URL using canvas.toDataURL(), and then use the dataURLtoBlob function from the previous example:

import { saveAs } from 'file-saver';

// Assuming you have a canvas element with id 'myCanvas'
const canvas = document.getElementById('myCanvas');
const dataUrl = canvas.toDataURL();
const blob = dataURLtoBlob(dataUrl);
saveAs(blob, 'my-canvas.png');

Remember to replace 'myCanvas' with the actual ID of your canvas element.

Handling user prompts and errors

While FileSaver.js generally handles the download process smoothly, you might want to handle potential issues. Although errors are rare, you can wrap the saveAs call in a try...catch block:

import { saveAs } from 'file-saver';

try {
  const blob = new Blob(['My file content'], {type: 'text/plain'});
  saveAs(blob, 'my-file.txt');
} catch (error) {
  console.error('Error saving file:', error);
  // Add user-friendly error handling here, e.g., display an alert message.
}

This improves robustness by providing a mechanism for handling unexpected problems.

Customizing the save dialog

FileSaver.js doesn’t directly provide options to extensively customize the browser’s save dialog. The dialog’s appearance and behavior are primarily controlled by the browser itself. However, ensuring correct MIME types and filenames gives the user the best chance of a smooth experience.

Working with different file types (e.g., images, PDFs)

FileSaver.js works seamlessly with various file types. The key is to use the appropriate MIME type when creating the Blob:

import { saveAs } from 'file-saver';

// PDF
const pdfBlob = new Blob([pdfDocumentData], {type: 'application/pdf'});  //Replace pdfDocumentData with your PDF data
saveAs(pdfBlob, 'my-document.pdf');

// Image (assuming you have image data as a Uint8Array)
const imageBlob = new Blob([imageData], {type: 'image/jpeg'});
saveAs(imageBlob, 'my-image.jpg');

Remember that the pdfDocumentData and imageData placeholders must be replaced with your actual data.

Asynchronous operations

The saveAs function is asynchronous. While it doesn’t use Promises directly, the download process happens in the background. This means your code will continue executing after calling saveAs without waiting for the download to complete. This behavior is usually desirable; however, if you need to know when the download finishes, consider using events provided by the browser (which are outside the scope of FileSaver.js itself). For example, you could check the download progress via browser dev tools’ network tab.

API Reference

saveAs() method parameters and return values

The core function of FileSaver.js is saveAs(). It takes two parameters:

saveAs(blob, filename, [options]); 

The saveAs() function itself doesn’t return any value. The download process happens asynchronously in the background.

Detailed explanation of each parameter

Error handling and exceptions

FileSaver.js generally handles the file saving process robustly. However, errors can occur due to issues like browser limitations or incorrect usage. While FileSaver.js doesn’t throw specific exceptions itself, problems might manifest as the file download failing to initiate or the save dialog not appearing. Therefore, good practice involves wrapping the saveAs call in a try...catch block to handle potential errors:

import { saveAs } from 'file-saver';

try {
  const blob = new Blob(['My file content'], {type: 'text/plain'});
  saveAs(blob, 'my-file.txt');
} catch (error) {
  console.error('An error occurred while saving the file:', error);
  // Add user-friendly error handling here (e.g., display an alert to the user).
}

This approach allows for better error management and provides a way to gracefully handle situations where the file saving operation fails. Note that the error object might not always contain detailed information about the failure, especially in older browser versions. In such cases, error handling should primarily focus on preventing the application from crashing and providing feedback to the user.

Examples

Saving text files

This example demonstrates saving a simple text file:

import { saveAs } from 'file-saver';

const text = "This is the content of my text file.";
const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
saveAs(blob, 'my-text-file.txt');

Saving image files

To save an image file, you’ll typically start with image data (e.g., from a canvas element or a data URL). This example assumes you have image data as a Uint8Array:

import { saveAs } from 'file-saver';

//  Replace 'imageData' with your actual image data (Uint8Array)
const imageData = new Uint8Array([/* ... your image data ... */]); 
const blob = new Blob([imageData], { type: 'image/jpeg' });
saveAs(blob, 'my-image.jpg');

Saving CSV files

This example saves a CSV file with comma-separated values:

import { saveAs } from 'file-saver';

const csvData = "Name,Age,City\nJohn Doe,30,New York\nJane Doe,25,London";
const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8' });
saveAs(blob, 'my-data.csv');

Saving JSON files

Saving JSON data involves creating a Blob from a JSON string:

import { saveAs } from 'file-saver';

const jsonData = JSON.stringify({ name: "John Doe", age: 30, city: "New York" });
const blob = new Blob([jsonData], { type: 'application/json;charset=utf-8' });
saveAs(blob, 'my-data.json');

Complex example: combining multiple data sources

This example demonstrates combining data from different sources into a single downloadable file (a zip archive in this case). Note that this requires a library to create the zip archive; this is just illustrative and you would need to include a suitable library like JSZip.

import { saveAs } from 'file-saver';
import JSZip from 'jszip'; // You'll need to install jszip: npm install jszip

async function saveCombinedData() {
  const zip = new JSZip();

  // Add text file
  zip.file("data.txt", "This is some text data.");

  // Add JSON data
  zip.file("data.json", JSON.stringify({ a: 1, b: 2 }));

  // Assuming you have image data as a Uint8Array
  const imageData = new Uint8Array([/* ... your image data ... */]);
  zip.file("image.jpg", imageData, {binary:true});


  const content = await zip.generateAsync({ type: "blob" });
  saveAs(content, "combined_data.zip");
}

saveCombinedData();

This advanced example shows how FileSaver.js integrates with other libraries to handle more complex file types and data combinations. Remember to replace placeholder data with your actual data and install the necessary libraries.

Troubleshooting

Common errors and solutions

Debugging tips

Browser-specific issues

Although FileSaver.js aims for cross-browser compatibility, minor inconsistencies might exist. Here are some potential browser-specific considerations:

If you encounter persistent issues that don’t align with the common errors listed above, please provide detailed information about your setup, code snippet, browser, and observed behavior to facilitate more effective troubleshooting. Consulting the FileSaver.js GitHub repository’s issues section might also reveal solutions to previously encountered problems.

Contributing

Reporting bugs

If you discover a bug in FileSaver.js, please report it on the project’s GitHub issue tracker. When reporting a bug, please provide the following information:

Clear and concise bug reports greatly assist in identifying and resolving issues efficiently.

Suggesting features

If you have an idea for a new feature or improvement to FileSaver.js, please suggest it on the GitHub issue tracker. When suggesting a feature, explain:

Well-reasoned feature suggestions increase the likelihood of your proposal being considered and potentially included in future releases.

Coding style guide

FileSaver.js follows a consistent coding style. If you contribute code, please adhere to the following guidelines:

Consistency in coding style improves code readability and maintainability.

Testing procedures

FileSaver.js uses a testing framework (likely Jest or similar). If you’re contributing code, you’re expected to write unit tests to ensure the functionality and correctness of your changes. The project’s README or CONTRIBUTING file usually contains detailed instructions on how to set up the development environment and run the tests. Before submitting a pull request, thoroughly test your code to verify that it works correctly and doesn’t introduce regressions. Testing is essential for maintaining the quality and stability of FileSaver.js. Adhering to existing testing practices will help integrate your changes seamlessly.