# API reference

> Reference for tabularjs(file, options) - accepted inputs, format detection, every option, the result shape, errors, limits and upgrading from 1.x.

Source: https://tabularjs.com/docs/api/

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

```ts
tabularjs(file: FileInput, options?: ParseOptions): Promise<ParseResult>
```

```js
import tabularjs from 'tabularjs';

const result = await tabularjs('report.xlsx');
```

:::tip[For AI agents]
This documentation is also available as plain text: [/llms.txt](/llms.txt) (index and rules for writing TabularJS code), [/llms-full.txt](/llms-full.txt) (everything in one file), and every page as Markdown by adding `.md` to its URL ([/docs/api.md](/docs/api.md)).
:::

## 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

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.

```js
// 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' });
```

## 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](https://encoding.spec.whatwg.org/#names-and-labels) (`'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`.

```js
// 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 });
```

## 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](/docs#output-structure) for every property. The result can be passed straight to Jspreadsheet.

## 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](#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.

```js
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

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.

## 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.** `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](/docs/changelog) for the full list of changes.
