DEV Community

Ryan
Ryan

Posted on

Download Multiple Files as a ZIP in React — Including Multi-GB Archives

A “Download all as ZIP” button in React starts simple. A production version also needs progress, cancellation, retry, useful errors, and a plan for archives that are too large for browser memory.

In this tutorial, we’ll use Eazip, an open-source ZIP toolkit for JavaScript and React. Its React package gives you a hook for starting ZIP jobs and a ready-made tray for showing their status.

Everyday files can be zipped entirely in the browser. When the same feature needs to handle multi-GB archives or thousands of remote URLs, it can move the job to Eazip Cloud without adding any backend code.

Install the React package

npm install @eazip/react
Enter fullscreen mode Exit fullscreen mode

@eazip/react requires React 18 or later. It includes the core ZIP engine, so you do not need to install another Eazip package.

Build a working ZIP download component

This component lets a user select several files and download them as one ZIP:

import { useState } from 'react';
import { EazipTray, useEazip } from '@eazip/react';

export function FileZipDownload() {
  const [files, setFiles] = useState<File[]>([]);
  const zip = useEazip();

  return (
    <section>
      <label>
        Files to download
        <input
          type="file"
          multiple
          onChange={(event) =>
            setFiles(Array.from(event.currentTarget.files ?? []))
          }
        />
      </label>

      <button
        type="button"
        disabled={files.length === 0 || zip.isBusy}
        onClick={() =>
          zip.download({
            files,
            zipName: 'selected-files.zip',
          })
        }
      >
        Download {files.length || ''} files as ZIP
      </button>

      <EazipTray />
    </section>
  );
}
Enter fullscreen mode Exit fullscreen mode

There are three Eazip pieces in this example:

  • useEazip() gives the component its download commands and current task.
  • zip.download() starts the ZIP job and returns immediately.
  • <EazipTray /> shows progress, cancel, retry, partial results, errors, and the completed download.

No provider or CSS import is required.

What happens to the selected files?

Without a strategy option, Eazip uses its Local strategy. The selected File objects stay on the user’s device and the ZIP is created in the browser.

That means there is:

  • no upload before the download can begin;
  • no server-side ZIP code to write;
  • no temporary archive to store and clean up.

The same files option also accepts FileList, Blob, URL strings, and source objects when you need to rename entries or create folders inside the ZIP:

zip.download({
  files: [
    { file: reportFile, filename: 'reports/annual.pdf' },
    { file: chartBlob, filename: 'reports/chart.png' },
  ],
  zipName: 'reports.zip',
});
Enter fullscreen mode Exit fullscreen mode

Remote URLs used in the browser must allow your application’s origin through CORS.

Handle multi-GB archives

Browser-side zipping is a good default, but browser memory and tab lifetime become limiting factors for multi-GB archives or thousands of files.

For a large archive built from remote URLs, keep the same hook and tray and change the execution strategy:

zip.download({
  strategy: 'cloud',
  publicKey: 'pk_ez_...',
  files: urls,
  zipName: 'media-export.zip',
});
Enter fullscreen mode Exit fullscreen mode

The ZIP job now runs on Eazip Cloud while the tray continues to show its progress and result. Cloud jobs can handle multi-GB archives, thousands of URLs, and jobs that need to survive a page reload.

The pk_ez_... value is a publishable browser key. Create one in Eazip and restrict it to your application’s allowed origins. No secret key or backend endpoint is needed for this frontend flow.

Cloud jobs use remote URL sources. Files that exist only as browser File or Blob objects should stay with the Local strategy because Eazip Cloud cannot access data that only exists on the user’s device.

Local or Cloud?

Use Local Use Cloud
The files are already in the browser The sources are remote URLs
The archive fits comfortably in browser memory The archive is multi-GB or contains thousands of URLs
Files should never leave the device The job must continue outside the browser tab
You want zero setup You can add a publishable key and allowed origin

Both strategies use the same useEazip() hook and <EazipTray />, so the visible download flow does not need to be rebuilt when the workload grows.

Where should the tray live?

If several components can start ZIP downloads, render one <EazipTray /> near the application root. Individual buttons can keep calling zip.download(), while the tray owns the visible task state.

If the status must fit an existing panel or toolbar, use the hook state directly and build a custom interface instead.

The complete examples and API details are available in the Eazip React ZIP download guide.

How does your React application handle “Download all” today—and what happens when the archive grows beyond browser memory?

Top comments (0)