DEV Community

Evan Mercer
Evan Mercer

Posted on

Handing several files to a browser user: zip or not

If your web tool produces exactly one file, you are fine. Content-Disposition: attachment, one click, done.

The moment it produces several files, you have a decision to make, and both options are worse than you expect.

Option A: trigger N downloads

The obvious approach is to create N anchors and click them in a loop.

for (const file of files) {
  const a = document.createElement('a');
  a.href = file.url;
  a.download = file.name;
  a.click();
}
Enter fullscreen mode Exit fullscreen mode

This works in a demo with two files and degrades badly after that.

Chrome treats a burst of programmatic downloads from one gesture as suspicious. The first one goes through; somewhere after that the user gets an "allow multiple downloads?" prompt, and if they miss it or dismiss it, the rest vanish silently. Your code has no idea. There is no error, no rejected promise, nothing to catch — the downloads just do not happen.

Safari on iOS is stricter still. A download not tied closely to a real user gesture tends to be dropped, and looping over anchors puts you well outside "closely".

You can paper over this with delays between clicks, and people do. It is a heuristic fighting a heuristic, and it breaks whenever the browser retunes the rule.

Option B: zip them server-side

One request, one file, one download. No multi-download prompt, no gesture heuristics, works the same on desktop and mobile.

The cost lands on the user instead. They now have an archive, and on a phone that means finding it, opening it, and extracting it — which on iOS is a real detour, and for someone who only wanted one of the images inside it is a bad trade.

There is a server cost too: you need every file in hand before you can send the first byte, or you need to stream the zip as you go, which rules out knowing the total size up front.

Where the line actually falls

After shipping both, the rule I ended up with is not about file count. It is about whether the files are one thing.

Images from a multi-photo post: zip. Four photos posted together are a set. Nobody wants the third one alone, the names are meaningless individually, and they are small enough that the archive is not a burden. One download, one folder, order preserved.

Video clips from a post with several videos: separate. A post with three clips is usually three separate things, they are large, and most people want one of them. Zipping forces someone who wanted a 4 MB clip to pull down 60 MB and unpack it to get at it.

That is the actual split in X Video Downloader, the small tool I maintain for saving public media from X: image carousels come back as a single archive, multiple video clips come back as one file each. It looks inconsistent in a feature list. In use it is the difference between "that did what I meant" and "why did it do that".

The bit that is easy to miss

Whichever you pick, decide what happens when the user only wants one item — and make that path exist. For a zip, that means the page still needs a per-file link next to the bundle. It is the cheapest thing in this whole post to build, and the one people reach for most.

The general version: "several files" is not one problem. It is two, and the shape of the files tells you which one you are looking at.

Top comments (1)

Collapse
 
beusebiu profile image
Eusebiu Balan •

For the photo case on phones, the share sheet is worth trying. navigator.share with a files array hands all four images over in one go, and on iOS the sheet offers to save them straight to Photos, which is where someone saving photos from a post wanted them anyway. A zip on an iPhone lands in Files and has to be unpacked first.

Check navigator.canShare({ files }) before offering it, and keep the zip for desktop.