Using TabularJS with Jspreadsheet
TabularJS is a zero-dependency JavaScript library that converts 16+ spreadsheet file formats — including XLSX, XLS, ODS, CSV, TSV, HTML tables, DBF, SYLK, DIF and Lotus 1-2-3 — into a clean JSON structure that Jspreadsheet (CE and Pro) can render natively.
This integration allows your users to drop any spreadsheet file onto a Jspreadsheet instance and see it loaded in the grid — with data, formulas, merged cells and styles preserved whenever the source format supports them.
Why TabularJS
- 16+ supported formats — XLSX, XLS, ODS, CSV, TSV, TXT, XML SpreadsheetML, HTML, DBF, SYLK, DIF, WK1/WK3/WK4/123.
- Zero dependencies — no SheetJS, no ExcelJS, pure JavaScript.
- Formula preservation — formulas are kept where the source format supports them.
- Styling and structure — merged cells, styles and comments are carried over where available.
- Universal runtime — works in the browser and in Node.js.
- Native Jspreadsheet shape — the output is directly compatible with
jspreadsheet()and@jspreadsheet/pro.
Installation
NPM
npm install tabularjs
CDN
<script src="https://cdn.jsdelivr.net/npm/tabularjs/dist/index.js"></script>
Quick Example
The example below lets the user pick a file, parses it with TabularJS and renders the result with Jspreadsheet.
<html>
<script src="https://bossanova.uk/jspreadsheet/v5/jspreadsheet.js"></script>
<script src="https://jsuites.net/v5/jsuites.js"></script>
<script src="https://cdn.jsdelivr.net/npm/tabularjs/dist/index.js"></script>
<link rel="stylesheet" href="https://bossanova.uk/jspreadsheet/v5/jspreadsheet.css" type="text/css" />
<link rel="stylesheet" href="https://jsuites.net/v5/jsuites.css" type="text/css" />
<input type="file" id="file" accept=".xlsx,.xls,.ods,.csv,.tsv,.html,.dbf,.slk,.dif" />
<div id="spreadsheet"></div>
<script>
document.getElementById('file').addEventListener('change', async function(e) {
const file = e.target.files[0];
// Parse any supported spreadsheet into JSON
const result = await tabularjs(file);
// Destroy any previous instance
jspreadsheet.destroy(document.getElementById('spreadsheet'));
// Create the spreadsheet directly from the parsed result
jspreadsheet(document.getElementById('spreadsheet'), result);
});
</script>
</html>
import React, { useRef } from 'react';
import jspreadsheet from 'jspreadsheet-ce';
import tabularjs from 'tabularjs';
import 'jsuites/dist/jsuites.css';
import 'jspreadsheet-ce/dist/jspreadsheet.css';
export default function App() {
const spreadsheet = useRef(null);
const input = useRef(null);
const load = async (e) => {
const file = e.target.files[0];
const result = await tabularjs(file);
// Clear any previous instance then render the parsed file
jspreadsheet.destroy(spreadsheet.current);
jspreadsheet(spreadsheet.current, result);
};
return (
<>
<input ref={input} type="file" onChange={load} style={{ display: 'none' }} />
<button onClick={() => input.current.click()}>Load file</button>
<div ref={spreadsheet}></div>
</>
);
}
<template>
<div>
<input ref="input" type="file" @change="load" style="display: none" />
<button @click="$refs.input.click()">Load file</button>
<div ref="spreadsheet"></div>
</div>
</template>
<script>
import jspreadsheet from 'jspreadsheet-ce';
import tabularjs from 'tabularjs';
import 'jsuites/dist/jsuites.css';
import 'jspreadsheet-ce/dist/jspreadsheet.css';
export default {
methods: {
async load(e) {
const file = e.target.files[0];
const result = await tabularjs(file);
jspreadsheet.destroy(this.$refs.spreadsheet);
jspreadsheet(this.$refs.spreadsheet, result);
}
}
}
</script>
import { Component, ViewChild, ElementRef } from '@angular/core';
import jspreadsheet from 'jspreadsheet-ce';
import tabularjs from 'tabularjs';
import 'jspreadsheet-ce/dist/jspreadsheet.css';
import 'jsuites/dist/jsuites.css';
@Component({
standalone: true,
selector: 'app-root',
template: `
<input type="file" (change)="load($event)" />
<div #spreadsheet></div>
`
})
export class AppComponent {
@ViewChild('spreadsheet') spreadsheet: ElementRef;
async load(e: Event) {
const file = (e.target as HTMLInputElement).files[0];
const result = await tabularjs(file);
jspreadsheet.destroy(this.spreadsheet.nativeElement);
jspreadsheet(this.spreadsheet.nativeElement, result);
}
}
Using TabularJS with Jspreadsheet Pro
Jspreadsheet Pro accepts the exact same configuration shape that TabularJS returns. A single call is enough to open the file in a Pro worksheet:
import jspreadsheet from '@jspreadsheet/pro';
import tabularjs from 'tabularjs';
const result = await tabularjs(file);
jspreadsheet(document.getElementById('spreadsheet'), result);
For a production-ready upload experience, Pro also exposes toolbars and a persistence layer you can wire directly to the parsed result.
Parsing in Node.js
TabularJS runs in Node.js with the same API — pass a file path or a Buffer instead of a File:
import fs from 'fs';
import tabularjs from 'tabularjs';
// Path
const result = await tabularjs('./sales.xlsx');
// Buffer
const buffer = fs.readFileSync('./sales.xlsx');
const fromBuffer = await tabularjs(buffer);
console.log(result.worksheets[0].data);
Supported formats
| Format | Extension | Formulas | Styles | Merged cells |
|---|---|---|---|---|
| Excel 97-2003 | .xls |
Yes | Yes | Yes |
| Excel 2007+ | .xlsx |
Yes | Yes | Yes |
| OpenDocument | .ods |
Yes | Yes | Yes |
| XML Spreadsheet 2003 | .xml |
Yes | Partial | Yes |
| SYLK | .slk, .sylk |
Yes | No | No |
| HTML Tables | .html, .htm |
Partial | Yes | Yes |
| CSV / TSV / TXT | .csv, .tsv, .tab, .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 |
Links
- Website: tabularjs.com
- GitHub: github.com/jspreadsheet/tabularjs
- NPM:
npm install tabularjs