Skip to content

Getting Started

TabularJS is a JavaScript library that converts spreadsheet files to JSON. It supports 16+ formats including Excel (.xls, .xlsx), OpenDocument (.ods), CSV, TSV, SYLK, DIF, dBase, Lotus 1-2-3, and HTML tables. It works in both Node.js and the browser, with only two small runtime dependencies (JSZip and an HTML table parser).

Terminal window
npm install tabularjs

Load TabularJS directly from a CDN in your HTML:

<script src="https://cdn.jsdelivr.net/npm/tabularjs/dist/index.min.js"></script>

MIT licensed: github.com/jspreadsheet/tabularjs

Pass a File object from a file input or drag-and-drop event. TabularJS parses it on the client side and returns JSON.

<html>
<script src="https://cdn.jsdelivr.net/npm/tabularjs/dist/index.min.js"></script>
<input type="file" id="fileInput" />
<pre id="output"></pre>
<script>
document.getElementById('fileInput').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (file) {
const result = await tabularjs(file);
document.getElementById('output').textContent = JSON.stringify(result, null, 2);
}
});
</script>
</html>

Pass a file path string. TabularJS reads the file from disk and returns the same JSON structure.

import tabularjs from 'tabularjs';
const result = await tabularjs('path/to/file.xlsx');
console.log(result.worksheets[0].data);

Pass a Uint8Array, ArrayBuffer or Node Buffer when the file does not come from disk or a file input (a fetch response, a database, an upload stream). The format is detected from the content; use extension to force it.

import tabularjs from 'tabularjs';
const response = await fetch('/reports/q3');
const bytes = new Uint8Array(await response.arrayBuffer());
const result = await tabularjs(bytes);
const csv = await tabularjs(bytes, { extension: 'csv' });

When a file name has no extension or an unknown one, TabularJS also falls back to detecting the format from the content.

Parse a spreadsheet file directly from the terminal:

Terminal window
node -e "import('tabularjs').then(m => m.default('file.xlsx').then(r => console.log(JSON.stringify(r, null, 2))))"

Or create a reusable script:

import fs from 'fs';
import tabularjs from 'tabularjs';
const filePath = process.argv[2];
if (!filePath) {
console.log('Usage: node script.js <path-to-file>');
process.exit(1);
}
if (!fs.existsSync(filePath)) {
console.error(`Error: File not found: ${filePath}`);
process.exit(1);
}
const result = await tabularjs(filePath);
console.log(JSON.stringify(result, null, 2));

Every file format produces the same JSON structure, ready to pass to Jspreadsheet:

{
"worksheets": [
{
"worksheetName": "Q1 Report",
"data": [
["Name", "Revenue", "Growth"],
["North", 42000, "=B2*1.1"],
["South", 48500, "=Data!B3*1.1"]
],
"columns": [
{ "title": "A", "width": 120, "type": "text" },
{ "title": "B", "width": 90 },
{ "title": "C", "width": 90 }
],
"rows": { "0": { "height": 24 } },
"cells": { "A1": { "align": "center" } },
"style": { "A1": 0, "B1": 1 },
"mergeCells": { "A5": [3, 1] },
"comments": { "B2": "Includes returns" },
"minDimensions": [3, 3]
}
],
"style": [
"font-weight: bold; text-align: center",
"text-align: right"
],
"definedNames": { "Totals": "Sheet1!$B$2:$B$3" }
}

Formulas are kept as text in data (with the leading =), so references to other sheets, named ranges and array constants come through as Excel wrote them.

Property Type Description
worksheetName string Sheet name (formats with a single table may omit it)
data any[][] 2D array of cell values: strings, numbers, booleans and formulas ("=SUM(A1:A3)")
columns object[] One entry per column: title, plus width, type, mask and others when the format has them
rows object Row metadata keyed by row index, e.g. { "0": { "height": 24 } }
cells object Per-cell properties keyed by address ("A1"): format, align, wrap… XLS and SYLK also copy each formula here as formula
style object Style of each cell, keyed by address: an index into the result’s style list
mergeCells object Merged ranges keyed by the top-left address, value [colspan, rowspan]
comments object Cell comments keyed by address
minDimensions [number, number] [columns, rows] of the used range
worksheetState string "hidden" or "veryHidden"; omitted for visible sheets
gridline boolean false when the sheet hides its gridlines
media object[] Images, charts and shapes (XLSX, ODS)
Property Type Description
worksheets object[] One worksheet per sheet in the file
style string[] Shared CSS styles referenced by each worksheet’s style (XLS, XLSX, ODS)
definedNames object Named ranges, name to reference (XLSX, ODS)

Rich formats like XLSX, XLS and ODS fill most of these properties. Text formats like CSV only emit data and columns. The full TypeScript definitions ship with the package (tabularjs/dist/index.d.ts).

Step-by-step guides for integrating TabularJS in your framework of choice.

TabularJS output is directly compatible with Jspreadsheet. Pass the result to jspreadsheet() to render uploaded files as live, editable spreadsheets.

<html>
<script src="https://cdn.jsdelivr.net/npm/jsuites/dist/jsuites.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jsuites/dist/jsuites.min.css" />
<script src="https://cdn.jsdelivr.net/npm/jspreadsheet-ce/dist/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jspreadsheet-ce/dist/jspreadsheet.min.css" />
<script src="https://cdn.jsdelivr.net/npm/tabularjs/dist/index.min.js"></script>
<div id="spreadsheet"></div>
<input type="file" id="fileInput" />
<script>
document.getElementById('fileInput').addEventListener('change', async (e) => {
const file = e.target.files[0];
if (file) {
const result = await tabularjs(file);
// tabs: true shows every worksheet of the file
jspreadsheet(document.getElementById('spreadsheet'), { ...result, tabs: true });
}
});
</script>
</html>
import { useRef } from 'react';
import jspreadsheet from 'jspreadsheet-ce';
import tabularjs from 'tabularjs';
export default function App() {
const spreadsheet = useRef(null);
const inputRef = useRef(null);
const handleFile = async (e) => {
const file = e.target.files[0];
if (file) {
const result = await tabularjs(file);
jspreadsheet(spreadsheet.current, result);
}
};
return (
<>
<div ref={spreadsheet}></div>
<input
ref={inputRef}
type="file"
onChange={handleFile}
style={{ display: 'none' }}
/>
<button onClick={() => inputRef.current.click()}>
Load File
</button>
</>
);
}
Format Extension Formulas Styles Merged Cells
Excel 97-2003 .xls Yes Yes Yes
Excel 2007+ .xlsx Yes Yes Yes
OpenDocument .ods Yes Yes Yes
HTML Tables .html, .htm Partial Yes Yes
XML Spreadsheet 2003 .xml Yes No Yes
SYLK .slk, .sylk Yes No No
CSV .csv No No No
TSV .tsv, .tab No No No
Plain Text .txt No No No
DIF .dif No No No
dBase .dbf No No No
Lotus 1-2-3 .wks, .wk1, .wk3, .wk4, .123 No No No

See the full supported formats gallery for per-format details and examples.

TabularJS ships with TypeScript definitions. Import it normally and you get full type safety:

import tabularjs from 'tabularjs';
const result = await tabularjs('data.xlsx');
// result is fully typed
result.worksheets.forEach((sheet) => {
console.log(sheet.data);
});

TabularJS includes 540 test cases covering all supported formats:

Terminal window
npm test