Build real
.xlsx(Excel) files in the browser with zero dependencies. ~5 KB, one function.
Most JavaScript XLSX libraries (SheetJS, ExcelJS) ship 200–600 KB to your users. If all you need is "give the user an Excel file with a few sheets and rows", you don't need that.
mini-xlsx is the ~300-line function I extracted from
Mubsira Business — a free,
offline-first invoice + expense tracker — where it powers the
"send to accountant" export.
- ✅ Multiple named sheets
- ✅ Styled, frozen header row (teal)
- ✅ Auto-column widths
- ✅ Auto-detected types: numbers, ISO dates (
YYYY-MM-DD→ real Excel date), strings - ✅ Per-sheet
AutoFilter - ✅ Sheet names auto-truncated to Excel's 31-char limit
- ✅ Pure ES5, runs in any modern browser & Node 18+
- ❌ No dependencies. No SheetJS. No JSZip. No
Buffer. Nothing.
Just copy mini-xlsx.js into your project. That's it.
<script src="mini-xlsx.js"></script>Or npm install mini-xlsx (once published) — then:
const miniXlsx = require("mini-xlsx");const bytes = miniXlsx([
{
name: "Invoices",
headers: ["ID", "Client", "Date", "Amount"],
rows: [
["INV-001", "ACME Corp", "2026-04-24", 1250.00],
["INV-002", "Globex", "2026-04-25", 890.50],
],
},
{
name: "Expenses",
headers: ["Date", "Vendor", "Amount"],
rows: [
["2026-04-20", "Office Depot", 42.99],
],
},
]);
// Browser: trigger a download
const blob = new Blob([bytes], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
const url = URL.createObjectURL(blob);
const a = Object.assign(document.createElement("a"),
{ href: url, download: "report.xlsx" });
a.click();
URL.revokeObjectURL(url);
// Node:
require("fs").writeFileSync("report.xlsx", Buffer.from(bytes));See example.html for a complete working demo.
type Sheet = {
name: string; // truncated to 31 chars
headers: string[];
rows: Array<Array<string | number>>;
};| Cell value | Stored as |
|---|---|
42, 42.5, "42.5" |
Number |
"2026-04-24" (ISO date) |
Excel date |
| anything else | Shared string |
I needed a "send to accountant" feature in my offline PWA. Loading 600 KB of SheetJS for a 20 KB output file felt absurd, especially when the whole app is designed to work offline and stay tiny. So I wrote the minimum amount of OOXML (a ZIP container + 7 small XML files) needed to satisfy Excel, LibreOffice, and Google Sheets.
If you want to see it running in production, the full app is here: 👉 https://www.mubsiraanalytics.com/business/
- No formulas (use a real library if you need this)
- No images, no charts, no merged cells
- No streaming — keep workbooks under ~50 MB of data
- ZIP uses
STORED(no compression). Files are bigger than they could be, but Excel/LibreOffice/Google Sheets all accept this and the implementation stays tiny.
MIT — do whatever you want.
Extracted from Mubsira Business, a free offline-first invoice & expense tracker (no signup, your data stays on your device).