TabularJS
Alternatives

TabularJS vs SheetJS (xlsx)

SheetJS (the xlsx package) is the de-facto JavaScript Excel library — but it is also large, has a dual-license model, and exposes a low-level workbook/worksheet API that most applications end up wrapping. TabularJS offers the same core use case — reading a spreadsheet file into JSON — behind a single async call, with zero dependencies and a unified output across 16+ formats.

At a glance

FeatureTabularJSSheetJS (xlsx)
DependenciesZeroBundled CFB + codepage + others
LicenseMITApache 2.0 (Pro tier commercial)
Formats read16+ (XLSX, XLS, ODS, CSV, HTML, DBF, SYLK, DIF, Lotus)Many, depending on build
API surfaceSingle await tabularjs(file) callworkbook → sheet → cell helpers
Output shapeWorksheet-first JSON, drop-in for JspreadsheetWorkbook object, needs utils to convert
Write / mutate workbooksRead-onlyYes
Runs in Node & browserYesYes

Use SheetJS if you need to write workbooks, author formulas programmatically or do complex workbook manipulation. Use TabularJS if you only need to read files into JSON — that is the overwhelming majority of upload and ETL paths.

Migration: Node.js

A typical SheetJS read loop looks like this:

sheetjs.jsjs
import * as XLSX from 'xlsx';
import fs from 'fs';

const buffer = fs.readFileSync('./sales.xlsx');
const workbook = XLSX.read(buffer, { type: 'buffer' });

const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const rows = XLSX.utils.sheet_to_json(worksheet, { header: 1 });

console.log(rows);

The same thing with TabularJS is a single call:

tabularjs.jsjs
import tabularjs from 'tabularjs';

const result = await tabularjs('./sales.xlsx');

console.log(result.worksheets[0].data);

TabularJS detects the format from the path or file contents, so the same call works for .xlsx, .xls, .ods, .csv, .html and the rest.

Migration: browser upload

before.jsjs
// With SheetJS
input.addEventListener('change', async (e) => {
    const data = await e.target.files[0].arrayBuffer();
    const workbook = XLSX.read(data);
    const rows = XLSX.utils.sheet_to_json(
        workbook.Sheets[workbook.SheetNames[0]],
        { header: 1 }
    );
    render(rows);
});
after.jsjs
// With TabularJS
input.addEventListener('change', async (e) => {
    const result = await tabularjs(e.target.files[0]);
    render(result.worksheets[0].data);
});

No ArrayBuffer conversion, no sheet-name lookup, no utils.sheet_to_json.

Migration: rendering in Jspreadsheet

With SheetJS you typically convert cells, then re-map them into Jspreadsheet's data/columns shape. TabularJS returns that shape directly:

upload.jsjs
import jspreadsheet from 'jspreadsheet-ce';
import tabularjs from 'tabularjs';

input.addEventListener('change', async (e) => {
    const result = await tabularjs(e.target.files[0]);

    // The shape matches jspreadsheet() 1:1 — no mapping required
    jspreadsheet(target, result);
});

What you keep

Ready to switch?

Install TabularJS and replace your SheetJS read calls in a single commit.