Most developers reach for server-side tools when they need to work with ZIP files. But what if your users are uploading sensitive documents (legal filings, medical records, financial data) and you can't — or shouldn't — send them to a server?
Here's how to parse ZIP archives entirely in the browser using JSZip.
Setup
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
Or for offline use, bundle jszip.min.js locally (~100KB gzipped).
Reading a File Input
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', async (e) => {
const file = e.target.files[0];
const arrayBuffer = await file.arrayBuffer();
const zip = await JSZip.loadAsync(arrayBuffer);
// List all entries
zip.forEach((relativePath, zipEntry) => {
console.log(relativePath, zipEntry.dir ? '📁' : '📄');
});
});
Extracting Text Files
const contentXml = zip.file("content.xml");
if (contentXml) {
const text = await contentXml.async("string"); // UTF-8 text
console.log(text);
}
Extracting Binary Files as Base64
for (const [path, entry] of Object.entries(zip.files)) {
if (path.match(/\.(png|jpg|jpeg)$/i)) {
const base64 = await entry.async("base64");
const img = document.createElement("img");
img.src = `data:image/png;base64,${base64}`;
document.body.appendChild(img);
}
}
Creating ZIP Files
const zip = new JSZip();
zip.file("content.xml", '<template format_id="1.8">...</template>');
zip.file("images/logo.png", base64Data, { base64: true });
const blob = await zip.generateAsync({
type: "blob",
compression: "DEFLATE",
compressionOptions: { level: 6 }
});
// Trigger download
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "document.udf";
a.click();
Performance Considerations
| File Size | Parse Time (M1 Mac, Chrome) |
|---|---|
| 50 KB | ~5ms |
| 1 MB | ~25ms |
| 10 MB | ~180ms |
| 50 MB | ~900ms |
For files >10MB, consider using zip.generateAsync() with a progress callback:
const blob = await zip.generateAsync({ type: "blob" }, (metadata) => {
console.log(`Progress: ${metadata.percent.toFixed(1)}%`);
});
Real-World Use Case: udf2md
We used this approach in udf2md to convert Turkey's UYAP court documents (.udf) to Markdown — entirely in the browser. Zero backend, full GDPR/KVKK compliance.
The key insight: if you never send data to a server, you never have a data breach.
Top comments (0)