Skip to content

API reference

TabularJS has a single function. It takes a file in any supported format and resolves with the same JSON structure for all of them.

tabularjs(file: FileInput, options?: ParseOptions): Promise<ParseResult>
import tabularjs from 'tabularjs';
const result = await tabularjs('report.xlsx');
Input Environment Example
File path Node.js tabularjs('./data/sales.xlsx')
File / Blob Browser tabularjs(input.files[0])
Uint8Array, ArrayBuffer, Node Buffer Both tabularjs(await response.arrayBuffer())
HTML string Both tabularjs('<table>...</table>')
DOM element Browser tabularjs(document.querySelector('table'))

A string that starts with < (leading whitespace allowed) is parsed as HTML; any other string is a file path.

  1. options.extension, when given. It is never overridden.
  2. The extension of the file name (path or File.name), checked against the content:
    • when the bytes clearly belong to another format (an .xlsx renamed .xls, an .xls saved as .xlsx), the real format is used;
    • when the parser for the extension fails and the content looks like another format (a CSV, HTML or XML 2003 file saved as .xls, which is common), that format is tried. If it fails too, you get the first error.
  3. The content of the file, when there is no name, no extension, or an extension TabularJS does not know. Zip containers (XLSX, ODS, Numbers), OLE2 (XLS), Lotus, dBase, SYLK, DIF, XML Spreadsheet, HTML, CSV and TSV are recognized from their bytes.
// No file name: detected from the bytes
const result = await tabularjs(new Uint8Array(buffer));
// A .dat file that is really CSV
const csv = await tabularjs('export.dat', { extension: 'csv' });
Option Type Default Applies to Description
extension string (detected) All Force a format: 'xlsx', 'csv', '.html'…
delimiter string ',' for CSV, tab for TXT CSV, TXT Column separator. .tsv and .tab files always use tabs
encoding string 'utf-8' (CSV, TSV, TXT, SYLK); detected (DIF); the file’s codepage (DBF) CSV, TSV, TXT, SYLK, DIF, DBF Text encoding: any WHATWG label ('latin1', 'windows-1251', 'shift_jis'…). In Node.js, DOS codepages such as 'cp437' and 'cp850' also work through iconv-lite
tableIndex number (all tables) HTML Return only this table (0-based). Without it, every <table> becomes a worksheet
firstRowAsHeader boolean true HTML Use the first row as column titles instead of data
onload (result) => void All Called with the result when parsing succeeds
onerror (error) => void All Called with the error when parsing fails

The returned promise is the main interface; onload and onerror are there for callback-style code. An unsupported format is reported before any parser runs, so it rejects the promise without calling onerror.

// Semicolon-separated text file in a legacy Windows encoding
const result = await tabularjs(file, { extension: 'csv', delimiter: ';', encoding: 'windows-1252' });
// The second table of a page, keeping its first row as data
const table = await tabularjs(html, { tableIndex: 1, firstRowAsHeader: false });

tabularjs resolves with { worksheets: [...] }, plus a shared style list and definedNames when the format has them. Each worksheet holds data (a 2D array, with formulas as text such as "=SUM(A1:A3)") and, depending on the format, worksheetName, columns, rows, cells, style, mergeCells, comments and more.

See Output structure for every property. The result can be passed straight to Jspreadsheet.

Errors reject the promise (and call onerror when given). The most common ones:

Message Cause
Unsupported file type: ... The format is not supported, or could not be recognized from a file without an extension
Invalid file: must be a file path, File, Blob, Uint8Array, ArrayBuffer, or Buffer The input is not one of the accepted inputs
Workbook is encrypted with a password The .xls or .xlsx file is protected with a password to open
Workbook is encrypted (XOR obfuscation); decryption is not supported The .xls file uses an encryption TabularJS cannot read (also RC4 CryptoAPI)
No table elements found in HTML The HTML has no <table>
Table index 3 out of range. Found 2 tables. tableIndex is larger than the number of tables
Zip entry '...' exceeds the decompression limit of ... bytes (possible zip bomb) An XLSX, ODS or Numbers part inflates beyond the safety limit
Encoding '...' requires iconv-lite package A DOS codepage was requested in an environment without iconv-lite

Workbooks that are only write-protected (“read-only recommended” in Excel) are not an error: they open normally.

try {
const result = await tabularjs(upload);
} catch (err) {
if (/encrypted/.test(err.message)) {
// Ask the user to save the file without a password
}
}

TabularJS is designed to parse files uploaded by untrusted users:

  • Zip bombs: every entry of an XLSX, ODS or Numbers file is capped at 256 MB once decompressed, counted on the actual inflated bytes rather than the size the file declares.
  • Crafted .xls files: memory allocations are limited to the size of the container, and sector chains that loop are rejected.
  • Truncated files: an .xls cut short by a failed download returns the part that could be read instead of failing.
  • No code execution: formulas are returned as text and never evaluated; macros are ignored.
  • Node.js imports work. 1.x could not be imported in Node.js because of a packaging bug. No code change is needed.
  • HTML returns every table. worksheets now has one entry per <table>, named Table1, Table2… worksheets[0] is still the first table. Pass tableIndex to get only one.
  • Bytes need no file name. Pass a Uint8Array, ArrayBuffer or Buffer directly. There is no name or format option: use extension to force a format.
  • Optional encodings in Node.js. iconv-lite and chardet are now optional dependencies. They install by default; with npm install --omit=optional, DOS codepages (cp437, cp850…) are not available.
  • Undecodable .xls formulas now show the value Excel saved for the cell instead of =ERROR.

See the changelog for the full list of changes.