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');Inputs
Section titled “Inputs”| 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.
How the format is chosen
Section titled “How the format is chosen”options.extension, when given. It is never overridden.- The extension of the file name (path or
File.name), checked against the content:- when the bytes clearly belong to another format (an
.xlsxrenamed.xls, an.xlssaved 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.
- when the bytes clearly belong to another format (an
- 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 bytesconst result = await tabularjs(new Uint8Array(buffer));
// A .dat file that is really CSVconst csv = await tabularjs('export.dat', { extension: 'csv' });Options
Section titled “Options”| 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 encodingconst result = await tabularjs(file, { extension: 'csv', delimiter: ';', encoding: 'windows-1252' });
// The second table of a page, keeping its first row as dataconst table = await tabularjs(html, { tableIndex: 1, firstRowAsHeader: false });Result
Section titled “Result”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
Section titled “Errors”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 }}Security and limits
Section titled “Security and limits”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
.xlsfiles: memory allocations are limited to the size of the container, and sector chains that loop are rejected. - Truncated files: an
.xlscut 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.
Upgrading from 1.x
Section titled “Upgrading from 1.x”- 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.
worksheetsnow has one entry per<table>, namedTable1,Table2…worksheets[0]is still the first table. PasstableIndexto get only one. - Bytes need no file name. Pass a
Uint8Array,ArrayBufferorBufferdirectly. There is nonameorformatoption: useextensionto force a format. - Optional encodings in Node.js.
iconv-liteandchardetare now optional dependencies. They install by default; withnpm install --omit=optional, DOS codepages (cp437,cp850…) are not available. - Undecodable
.xlsformulas now show the value Excel saved for the cell instead of=ERROR.
See the changelog for the full list of changes.

