Skip to content

MubsiraAnalytics/mini-xlsx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mini-xlsx

Build real .xlsx (Excel) files in the browser with zero dependencies. ~5 KB, one function.

License: MIT Zero deps Browser

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.

Features

  • ✅ 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.

Install

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");

Usage

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.

Sheet object shape

type Sheet = {
  name: string;          // truncated to 31 chars
  headers: string[];
  rows: Array<Array<string | number>>;
};

Cell type detection

Cell value Stored as
42, 42.5, "42.5" Number
"2026-04-24" (ISO date) Excel date
anything else Shared string

Why I built this

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/

Limitations (by design)

  • 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.

License

MIT — do whatever you want.

Credits

Extracted from Mubsira Business, a free offline-first invoice & expense tracker (no signup, your data stays on your device).