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