This commit is contained in:
SheetJS 2023-06-13 13:49:52 -04:00
parent 063aec617b
commit 21e8d777ed
10 changed files with 796 additions and 418 deletions

@ -64,9 +64,9 @@ The raw data is an Array of objects. This is the data for John Adams:
"gender": "M"
},
"terms": [
{ "type": "viceprez", /* (other fields omitted) */ },
{ "type": "viceprez", /* (other fields omitted) */ },
{ "type": "prez", /* (other fields omitted) */ }
{ "type": "viceprez", "start": "1789-04-21", /* (other fields omitted) */ },
{ "type": "viceprez", "start": "1793-03-04", /* (other fields omitted) */ },
{ "type": "prez", "start": "1797-03-04", /* (other fields omitted) */ }
]
}
```
@ -89,7 +89,7 @@ const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez")
The dataset is sorted in chronological order by the first presidential or vice
presidential term. The Vice President and President in a given term are sorted
alphabetically. Joe Biden and Barack Obama were Vice President and President
respectively in 2009. Since "Biden" is lexicographically before "Obama", Biden's
respectively in 2009. Since "Biden" is alphabetically before "Obama", Biden's
data point appears first. The goal is to sort the presidents in order of their
presidential term.

@ -6,6 +6,8 @@ sidebar_position: 1
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
ReactJS is a JS library for building user interfaces.
@ -42,28 +44,19 @@ depends on the application.
### Array of Objects
Typically, some users will create a spreadsheet with source data that should be
loaded into the site. This sheet will have known columns. For example, our
[presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns:
loaded into the site. This sheet will have known columns.
#### State
The example [presidents sheet](https://sheetjs.com/pres.xlsx) has one header row
with "Name" and "Index" columns. The natural JS representation is an object for
each row, using the values in the first rows as keys:
<table><thead><tr><th>Spreadsheet</th><th>State</th></tr></thead><tbody><tr><td>
![`pres.xlsx` data](pathname:///pres.png)
This naturally maps to an array of typed objects, as in the TS example below:
```ts
import { read, utils } from 'xlsx';
interface President {
Name: string;
Index: number;
}
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
const wb = read(f);
const data = utils.sheet_to_json<President>(wb.Sheets[wb.SheetNames[0]]);
console.log(data);
```
`data` will be an array of objects:
</td><td>
```js
[
@ -75,8 +68,177 @@ console.log(data);
]
```
A component will typically map over the data. The following example generates
a TABLE with a row for each President:
</td></tr></tbody></table>
The React `useState` hook can configure the state:
<Tabs groupId="lang">
<TabItem name="JS" value="JavaScript">
```ts
import { useState } from 'react';
/* the component state is an array of presidents */
const [pres, setPres] = useState([]);
```
</TabItem>
<TabItem name="TS" value="TypeScript" default>
```ts
import { useState } from 'react';
interface President {
Name: string;
Index: number;
}
/* the component state is an array of presidents */
const [pres, setPres] = useState<President[]>([]);
```
:::note
The types are informative. They do not enforce that worksheets include the named
columns. A runtime data validation library should be used to verify the dataset.
:::
</TabItem>
</Tabs>
#### Updating State
The [`read`](/docs/api/parse-options) and [`sheet_to_json`](/docs/api/utilities/array#array-output)
functions simplify state updates. They are best used in the function bodies of
`useEffect` and `useCallback` hooks.
A `useEffect` hook can download and update state when a person loads the site:
```mermaid
flowchart LR
url[(Remote\nFile)]
ab[(Data\nArrayBuffer)]
wb(SheetJS\nWorkbook)
ws(SheetJS\nWorksheet)
aoo(array of\nobjects)
state((component\nstate))
url --> |fetch\n\n| ab
ab --> |read\n\n| wb
wb --> |wb.Sheets\nselect sheet| ws
ws --> |sheet_to_json\n\n| aoo
aoo --> |setPres\nfrom `setState`| state
```
<Tabs groupId="lang">
<TabItem name="JS" value="JavaScript">
```ts
import { useEffect } from 'react';
import { read, utils } from 'xlsx';
/* Fetch and update the state once */
useEffect(() => { (async() => {
/* Download file */
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
// highlight-start
const wb = read(f); // parse the array buffer
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
const data = utils.sheet_to_json(ws); // generate objects
setPres(data); // update state
// highlight-end
})(); }, []);
```
</TabItem>
<TabItem name="TS" value="TypeScript" default>
```ts
import { useEffect } from 'react';
import { read, utils } from 'xlsx';
/* Fetch and update the state once */
useEffect(() => { (async() => {
/* Download file */
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
// highlight-start
const wb = read(f); // parse the array buffer
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
const data: President[] = utils.sheet_to_json<President>(ws); // generate objects
setPres(data); // update state
// highlight-end
})(); }, []);
```
</TabItem>
</Tabs>
#### Rendering Data
Components typically render HTML tables from arrays of objects. The `<tr>` table
row elements are typically generated by mapping over the state array, as shown
in the example JSX code:
```jsx title="Example JSX for displaying arrays of objects"
<table>
{/* The `thead` section includes the table header row */}
<thead><th>Name</th><th>Index</th></thead>
{/* The `tbody` section includes the data rows */}
<tbody>
{/* generate row (TR) for each president */}
// highlight-start
{pres.map(row => (
<tr>
{/* Generate cell (TD) for name / index */}
<td>{row.Name}</td>
<td>{row.Index}</td>
</tr>
))}
// highlight-end
</tbody>
</table>
```
#### Exporting Data
The [`writeFile`](/docs/api/write-options) and [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input)
functions simplify exporting data. They are best used in the function bodies of
`useCallback` hooks attached to button or other elements.
A callback can generate a local file when a user clicks a button:
```mermaid
flowchart LR
state((component\nstate))
ws(SheetJS\nWorksheet)
wb(SheetJS\nWorkbook)
file[(XLSX\nexport)]
state --> |json_to_sheet\n\n| ws
ws --> |book_new\nbook_append_sheet| wb
wb --> |writeFile\n\n| file
```
```ts
import { useCallback } from 'react';
import { utils, writeFile } from 'xlsx';
/* get state data and export to XLSX */
const exportFile = useCallback(() => {
/* generate worksheet from state */
// highlight-next-line
const ws = utils.json_to_sheet(pres);
/* create workbook and append worksheet */
const wb = utils.book_new();
utils.book_append_sheet(wb, ws, "Data");
/* export to XLSX */
writeFile(wb, "SheetJSReactAoO.xlsx");
}, [pres]);
```
#### Complete Component
This complete component example fetches a test file and displays the contents in
a HTML table. When the export button is clicked, a callback will export a file:
```jsx title="src/SheetJSReactAoO.js"
import React, { useCallback, useEffect, useState } from "react";

@ -2,6 +2,9 @@
sidebar_position: 3
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# Sheet Objects
Excel supports 4 different types of "sheets":
@ -36,19 +39,49 @@ large worksheets, dense sheets use less memory and tend to be more efficient.
sparse and dense worksheets. Functions that accept worksheet or workbook objects
(e.g. `writeFile` and `sheet_to_json`) will detect dense sheets.
The option `dense: true` should be used when creating worksheet or book objects:
The option `dense: true` should be used when creating worksheet or book objects.
**Update code that manually searches for cells** (adding dense mode support):
_Addressing Cells_
<Tabs>
<TabItem value="es3" label="Works everywhere">
```diff
-var workbook = XLSX.read(data, {...opts});
+var workbook = XLSX.read(data, {...opts, dense: true});
-var sheet = XLSX.utils.aoa_to_sheet([[1,2,3],[4,5,6]], {...opts});
+var sheet = XLSX.utils.aoa_to_sheet([[1,2,3],[4,5,6]], {...opts, dense: true});
-var sheet = XLSX.utils.json_to_sheet([{x:1,y:2}], {...opts});
+var sheet = XLSX.utils.json_to_sheet([{x:1,y:2}], {...opts, dense: true});
-var cell = sheet["B7"];
+var cell = sheet["!data"] != null ? (sheet["!data"][6]||[])[1] : sheet["B3"];
```
</TabItem>
<TabItem value="es2020" label="New in 2020">
```diff
-var cell = sheet["B7"];
+var cell = sheet["!data"] != null ? sheet["!data"]?.[6]?.[1] : sheet["B3"];
```
</TabItem>
</Tabs>
The row and column can be calculated using `XLSX.utils.decode_cell`:
```diff
var addr = "B7";
-var cell = sheet[addr];
+var _addr = XLSX.utils.decode_cell(addr);
+var cell = sheet["!data"] != null ? sheet["!data"]?.[_addr.r]?.[_addr.c] : sheet[addr];
```
`XLSX.utils.encode_cell` will be using the desired row and column indices:
```diff
-var cell = sheet[XLSX.utils.encode_cell({r:R, c:C})];
+var cell = sheet["!data"] != null ? sheet["!data"]?.[R]?.[C] : sheet[XLSX.utils.encode_cell({r:R, c:C})];
```
_Looping across a Worksheet_
Code that manually loops over worksheet objects should test for `"!data"` key:
```js
@ -68,6 +101,34 @@ function log_all_cells(ws) {
}
```
**Update workbook and worksheet generation code**
_`read`_
```diff
-var workbook = XLSX.read(data, {...opts});
+var workbook = XLSX.read(data, {...opts, dense: true});
```
_`readFile`_
```diff
-var workbook = XLSX.readFile(data, {...opts});
+var workbook = XLSX.readFile(data, {...opts, dense: true});
```
_`aoa_to_sheet`_
```diff
-var sheet = XLSX.utils.aoa_to_sheet([[1,2,3],[4,5,6]], {...opts});
+var sheet = XLSX.utils.aoa_to_sheet([[1,2,3],[4,5,6]], {...opts, dense: true});
```
_`json_to_sheet`_
```diff
-var sheet = XLSX.utils.json_to_sheet([{x:1,y:2}], {...opts});
+var sheet = XLSX.utils.json_to_sheet([{x:1,y:2}], {...opts, dense: true});
```
</details>
### Sheet Properties

@ -7,27 +7,39 @@ sidebar_position: 4
<details>
<summary><b>File Format Support</b> (click to show)</summary>
Comments and Notes have evolved over the years. "Notes" (powered by VML) were
the original comments. "Comments" were added later.
Comments and Notes have evolved over the years.
Excel 2.0 - '95 "Notes" were displayed in a master list.
Excel '97 - 2019 "Comments" float over the sheet and support styling.
Excel 365 introduced "Threaded Comments" which do not support rich text but do
allow users to "reply". The original "Comments" were renamed to "Notes".
| Formats | Notes | Comment | Threaded |
|:------------------|:-----:|:-------:|:--------:|
| XLSX / XLSM | ✔ | ✔ | ✔ |
| XLSB | ✔ | ✔ | R |
| XLS | R | R | * |
| XLML | ✔ | ✔ | * |
| SYLK | | * | * |
| ODS / FODS / UOS | ✔ | R | * |
| NUMBERS | * | * | |
| XLSX / XLSM | ✕ | ✔ | ✔ |
| XLSB | ✕ | R | R |
| NUMBERS | ✕ | ✕ | R |
| XLS (BIFF8) | ✕ | ✔ | ✕ |
| XLML | ✕ | ✔ | ✕ |
| ODS / FODS / UOS | ✕ | ✔ | ✕ |
| SYLK | ✔ | ✕ | ✕ |
| XLS (BIFF5) | ✔ | ✕ | ✕ |
| XLS (BIFF 2/3/4) | ✔ | ✕ | ✕ |
Asterisks (*) mark features that are not supported by the file formats. Numbers
supports plaintext threaded comments but does not support Excel styled comments.
X (✕) marks features that are not supported by the file formats. For example,
the NUMBERS file format supports plaintext threaded comments but does not
support Excel styled comments or Excel legacy notes.
The letter R (R) marks features parsed but not written in the format.
:::note
[SheetJS Pro](https://sheetjs.com/pro) supports comment rich text and styling.
:::
</details>
## Basic Structure
@ -45,12 +57,12 @@ For example, the following snippet appends a cell comment into cell `A1`:
var cell = ws["A1"];
/* create comment array if it does not exist */
if(!cell.c) ws.A1.c = [];
if(!cell.c) cell.c = [];
/* create a comment part */
var comment_part = {
a:"SheetJS",
t:"I'm a little comment, short and stout!"
a: "SheetJS",
t: "I'm a little comment, short and stout!"
};
/* Add comment part to the comment array */

@ -27,6 +27,18 @@ It also supports NodeJS, ExtendScript applications, and Chromium extensions.
If `options` is omitted or if `bookType` is missing from the `options` object,
the output file format will be deduced from the filename extension.
**`XLSX.writeXLSX(wb, options)`**
**`XLSX.writeFileXLSX(wb, filename, options)`**
`writeXLSX` and `writeFileXLSX` are limited versions of `write` and `writeFile`.
They support writing to the XLSX file format.
For websites that exclusively export to XLSX, these functions can reduce the
size of the production site. The general `write` and `writeFile` functions are
more appropriate when exporting to XLS or XLSB or other formats.
<details><summary><b>NodeJS-specific methods</b> (click to show)</summary>
**`XLSX.writeFileAsync(filename, wb, cb)`**

@ -0,0 +1,407 @@
---
sidebar_position: 5
title: Arrays of Data
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Arrays of objects are a common data format in JavaScript database connectors
and other general data sources.
Numeric datasets commonly use arrays of arrays of numbers.
:::note
The examples are based on the following worksheet:
<table>
<tr><td>S</td><td>h</td><td>e</td><td>e</td><td>t</td><td>J</td><td>S</td></tr>
<tr><td>1</td><td>2</td><td> </td><td> </td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>2</td><td>3</td><td> </td><td> </td><td>6</td><td>7</td><td>8</td></tr>
<tr><td>3</td><td>4</td><td> </td><td> </td><td>7</td><td>8</td><td>9</td></tr>
<tr><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>0</td></tr>
</table>
:::
## Array of Arrays Input
**Create a worksheet from an array of arrays**
```js
var ws = XLSX.utils.aoa_to_sheet(aoa, opts);
```
`XLSX.utils.aoa_to_sheet` takes an array of arrays of JS values and returns a
worksheet resembling the input data. Values are interpreted as follows:
- Numbers, Booleans and Strings are stored as the corresponding types.
- Date objects are stored as Date cells or date codes (see `cellDates` option)
- Array holes and explicit `undefined` values are skipped.
- `null` values may be stubbed (see `sheetStubs` and `nullError` options)
- Cell objects are used as-is.
The function takes an options argument:
| Option Name | Default | Description |
| :---------- | :-----: | :--------------------------------------------------- |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`cellDates` | false | Store dates as type `d` (default is `n`) |
|`sheetStubs` | false | Create cell objects of type `z` for `null` values |
|`nullError` | false | If true, emit `#NULL!` error cells for `null` values |
The example worksheet can be generated with:
```js
var ws = XLSX.utils.aoa_to_sheet([
["S", "h", "e", "e", "t", "J", "S"],
[ 1, 2, , , 5, 6, 7],
[ 2, 3, , , 6, 7, 8],
[ 3, 4, , , 7, 8, 9],
[ 4, 5, 6, 7, 8, 9, 0]
]);
```
**Add data from an array of arrays to an existing worksheet**
```js
XLSX.utils.sheet_add_aoa(ws, aoa, opts);
```
`XLSX.utils.sheet_add_aoa` takes an array of arrays of JS values and updates an
existing worksheet object. It follows the same process as `aoa_to_sheet` and
accepts an options argument:
| Option Name | Default | Description |
| :---------- | :-----: | :--------------------------------------------------- |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`cellDates` | false | Store dates as type `d` (default is `n`) |
|`sheetStubs` | false | Create cell objects of type `z` for `null` values |
|`nullError` | false | If true, emit `#NULL!` error cells for `null` values |
|`origin` | | Use specified cell as starting point (see below) |
`origin` is expected to be one of:
| `origin` | Description |
| :--------------- | :-------------------------------------------------------- |
| (cell object) | Use specified cell (cell object) |
| (string) | Use specified cell (A1-Style cell) |
| (number >= 0) | Start from the first column at specified row (0-indexed) |
| -1 | Append to bottom of worksheet starting on first column |
| (default) | Start from cell `A1` |
The example worksheet can be built up in the order `A1:G1, A2:B4, E2:G4, A5:G5`:
```js
/* Initial row */
var ws = XLSX.utils.aoa_to_sheet([ "SheetJS".split("") ]);
/* Write data starting at A2 */
XLSX.utils.sheet_add_aoa(ws, [[1,2], [2,3], [3,4]], {origin: "A2"});
/* Write data starting at E2 */
XLSX.utils.sheet_add_aoa(ws, [[5,6,7], [6,7,8], [7,8,9]], {origin:{r:1, c:4}});
/* Append row */
XLSX.utils.sheet_add_aoa(ws, [[4,5,6,7,8,9,0]], {origin: -1});
```
## Array of Objects Input
**Create a worksheet from an array of objects**
```js
var ws = XLSX.utils.json_to_sheet(aoo, opts);
```
`XLSX.utils.json_to_sheet` takes an array of objects and returns a worksheet
with automatically-generated "headers" based on the keys of the objects. The
default column order is determined by the first appearance of the field using
`Object.keys`. The function accepts an options argument:
| Option Name | Default | Description |
| :---------- | :-----: | :--------------------------------------------------- |
|`header` | | Use specified field order (default `Object.keys`) ** |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`cellDates` | false | Store dates as type `d` (default is `n`) |
|`skipHeader` | false | If true, do not include header row in output |
|`nullError` | false | If true, emit `#NULL!` error cells for `null` values |
:::caution
All fields from each row will be written! `header` hints at a particular order
but is not exclusive. To remove fields from the export, filter the data source.
Some data sources have special options to filter properties. For example,
MongoDB will add the `_id` field when finding data from a collection:
```js
const aoo_with_id = await coll.find({}).toArray();
const ws = XLSX.utils.json_to_sheet(aoo_with_id); // includes _id column
```
This can be filtered out through the `projection` property:
```js
const aoo = await coll.find({}, {projection:{_id:0}}).toArray(); // no _id !
const ws = XLSX.utils.json_to_sheet(aoo);
```
If a data source does not provide a filter option, it can be filtered manually:
```js
const aoo = data.map(obj => Object.fromEntries(Object.entries(obj).filter(r => headers.indexOf(r[0]) > -1)));
```
:::
- If `header` is an array, missing keys will be added in order of first use.
- Cell types are deduced from the type of each value. For example, a `Date`
object will generate a Date cell, while a string will generate a Text cell.
- Null values will be skipped by default. If `nullError` is true, an error cell
corresponding to `#NULL!` will be written to the worksheet.
The example sheet cannot be reproduced using plain objects since JS object keys
must be unique. After replacing the second `e` and `S` with `e_1` and `S_1`:
```js
var ws = XLSX.utils.json_to_sheet([
{ S:1, h:2, t:5, J:6, S_1:7 },
{ S:2, h:3, t:6, J:7, S_1:8 },
{ S:3, h:4, t:7, J:8, S_1:9 },
{ S:4, h:5, e:6, e_1:7, t:8, J:9, S_1:0 },
], {header:["S","h","e","e_1","t","J","S_1"]});
```
Alternatively, a different set of unique headers can be used with `skipHeader`:
```js
var ws = XLSX.utils.json_to_sheet([
{ A: "S", B: "h", C: "e", D: "e", E: "t", F: "J", G: "S" },
{ A: 1, B: 2, E: 5, F: 6, G: 7 },
{ A: 2, B: 3, E: 6, F: 7, G: 8 },
{ A: 3, B: 4, E: 7, F: 8, G: 9 },
{ A: 4, B: 5, C: 6, D: 7, E: 8, F: 9, G: 0 },
], {header:["A","B","C","D","E","F","G"], skipHeader:true});
```
**Add data from an array of objects to an existing worksheet**
```js
XLSX.utils.sheet_add_json(ws, aoo, opts);
```
`XLSX.utils.sheet_add_json` takes an array of objects and updates an existing
worksheet object. It follows the same process as `json_to_sheet` and accepts
an options argument:
| Option Name | Default | Description |
| :---------- | :-----: | :--------------------------------------------------- |
|`header` | | Use specified column order (default `Object.keys`) |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`cellDates` | false | Store dates as type `d` (default is `n`) |
|`skipHeader` | false | If true, do not include header row in output |
|`nullError` | false | If true, emit `#NULL!` error cells for `null` values |
|`origin` | | Use specified cell as starting point (see below) |
`origin` is expected to be one of:
| `origin` | Description |
| :--------------- | :-------------------------------------------------------- |
| (cell object) | Use specified cell (cell object) |
| (string) | Use specified cell (A1-Style cell) |
| (number >= 0) | Start from the first column at specified row (0-indexed) |
| -1 | Append to bottom of worksheet starting on first column |
| (default) | Start from cell `A1` |
This example worksheet can be built up in the order `A1:G1, A2:B4, E2:G4, A5:G5`:
```js
/* Initial row */
var ws = XLSX.utils.json_to_sheet([
{ A: "S", B: "h", C: "e", D: "e", E: "t", F: "J", G: "S" }
], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true});
/* Write data starting at A2 */
XLSX.utils.sheet_add_json(ws, [
{ A: 1, B: 2 }, { A: 2, B: 3 }, { A: 3, B: 4 }
], {skipHeader: true, origin: "A2"});
/* Write data starting at E2 */
XLSX.utils.sheet_add_json(ws, [
{ A: 5, B: 6, C: 7 }, { A: 6, B: 7, C: 8 }, { A: 7, B: 8, C: 9 }
], {skipHeader: true, origin: { r: 1, c: 4 }, header: [ "A", "B", "C" ]});
/* Append row */
XLSX.utils.sheet_add_json(ws, [
{ A: 4, B: 5, C: 6, D: 7, E: 8, F: 9, G: 0 }
], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true, origin: -1});
```
:::note
If the `header` option is an array, `sheet_add_json` and `sheet_to_json` will
append missing elements.
This design enables consistent header order across calls:
```jsx live
function SheetJSHeaderOrder() {
/* Use shared header */
const header = [];
const ws1 = XLSX.utils.json_to_sheet([ {C: 2, D: 3}, ], {header});
XLSX.utils.sheet_add_json(ws1, [ {D: 1, C: 4}, ], {header, origin: -1, skipHeader: true});
/* only use header in first call */
const ws2 = XLSX.utils.json_to_sheet([ {C: 2, D: 3}, ], {header:[]});
XLSX.utils.sheet_add_json(ws2, [ {D: 1, C: 4}, ], {origin: -1, skipHeader: true});
return (<pre>
<b>Objects</b>
{"\n[\n { C: 2, D: 3 },\n { D: 1, C: 4 } // different key order\n]\n"}<br/>
<b>Worksheet when same `header` array is passed to `sheet_add_json`</b>
<div dangerouslySetInnerHTML={{__html:XLSX.utils.sheet_to_html(ws1)}}/>
<i>New contents of `header`</i><br/>
{JSON.stringify(header)}<br/>
<br/>
<b>Worksheet when no `header` property is passed to `sheet_add_json`</b>
<div dangerouslySetInnerHTML={{__html:XLSX.utils.sheet_to_html(ws2)}}/>
</pre>)
}
```
:::
## Array Output
<Tabs>
<TabItem name="JS" value="JavaScript">
```js
var arr = XLSX.utils.sheet_to_json(ws, opts);
var aoa = XLSX.utils.sheet_to_json(ws, {header: 1, ...other_opts});
```
</TabItem>
<TabItem name="TS" value="TypeScript">
:::caution
TypeScript types are purely informational. They are not included at run time
and do not influence the behavior of the `sheet_to_json` function.
**`sheet_to_json` does not perform field validation!**
:::
The main type signature treats each row as `any`:
```ts
const data: any[] = XLSX.utils.sheet_to_json(ws, opts);
```
The `any[][]` overload is designed for use with `header: 1` (array of arrays):
```ts
const aoa: any[][] = XLSX.utils.sheet_to_json(ws, { header: 1, ...other_opts });
```
An interface can be passed as a generic parameter. `sheet_to_json` will still
return an array of plain objects (the types do not affect runtime behavior):
```ts
interface President {
Name: string;
Index: number;
}
const data: President[] = XLSX.utils.sheet_to_json<President>(ws);
```
</TabItem>
</Tabs>
`XLSX.utils.sheet_to_json` generates an array of JS objects. The function takes
an options argument:
| Option Name | Default | Description |
| :---------- | :------: | :-------------------------------------------------- |
|`raw` | `true` | Use raw values (true) or formatted strings (false) |
|`range` | ** | Override Range (see table below) |
|`header` | | Control output format (see table below) |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`defval` | | Use specified value in place of null or undefined |
|`blankrows` | ** | Include blank lines in the output ** |
- `raw` only affects cells which have a format code (`.z`) field or a formatted
text (`.w`) field.
- If `header` is specified, the first row is considered a data row; if `header`
is not specified, the first row is the header row and not considered data.
- When `header` is not specified, the conversion will automatically disambiguate
header entries by affixing `_` and a count starting at `1`. For example, if
three columns have header `foo` the output fields are `foo`, `foo_1`, `foo_2`
- `null` values are returned when `raw` is true but are skipped when false.
- If `defval` is not specified, null and undefined values are skipped normally.
If specified, all null and undefined points will be filled with `defval`
- When `header` is `1`, the default is to generate blank rows. `blankrows` must
be set to `false` to skip blank rows.
- When `header` is not `1`, the default is to skip blank rows. `blankrows` must
be true to generate blank rows
`range` is expected to be one of:
| `range` | Description |
| :--------------- | :-------------------------------------------------------- |
| (number) | Use worksheet range but set starting row to the value |
| (string) | Use specified range (A1-Style bounded range string) |
| (default) | Use worksheet range (`ws['!ref']`) |
`header` is expected to be one of:
| `header` | Description |
| :--------------- | :-------------------------------------------------------- |
| `1` | Generate an array of arrays |
| `"A"` | Row object keys are literal column labels |
| array of strings | Use specified strings as keys in row objects |
| (default) | Read and disambiguate first row as keys |
- If header is not `1`, the row object will contain the non-enumerable property
`__rowNum__` that represents the row of the sheet corresponding to the entry.
- If header is an array, the keys will not be disambiguated. This can lead to
unexpected results if the array values are not unique!
For the example worksheet:
```jsx live
function SheetJSToJSON() {
/* original data */
var ws = XLSX.utils.aoa_to_sheet([
["S", "h", "e", "e", "t", "J", "S"],
[ 1, 2, , , 5, 6, 7],
[ 2, 3, , , 6, 7, 8],
[ 3, 4, , , 7, 8, 9],
[ 4, 5, 6, 7, 8, 9, 0]
]);
/* display JS objects with some whitespace */
const aoo = o => o.map(r => " " + JSON.stringify(r).replace(/,"/g, ', "').replace(/:/g, ": ").replace(/"([A-Za-z_]\w*)":/g, '$1:')).join("\n");
const aoa = o => o.map(r => " " + JSON.stringify(r).replace(/,/g, ', ').replace(/null/g, "")).join("\n");
return ( <pre>
<b>Worksheet (as HTML)</b>
<div dangerouslySetInnerHTML={{__html: XLSX.utils.sheet_to_html(ws)}}/>
<b>XLSX.utils.sheet_to_json(ws, {'{'} header: 1 {'}'}) [array of arrays]</b><br/>
[<br/>{aoa(XLSX.utils.sheet_to_json(ws, { header: 1 }))}<br/>]<br/><br/>
<b>XLSX.utils.sheet_to_json(ws) [objects with header disambiguation]</b><br/>
[<br/>{aoo(XLSX.utils.sheet_to_json(ws))}<br/>]<br/><br/>
<b>XLSX.utils.sheet_to_json(ws, {'{'} header: "A" {'}'}) [column names as keys]</b><br/>
[<br/>{aoo(XLSX.utils.sheet_to_json(ws, { header: "A" }))}<br/>]<br/><br/>
<b>XLSX.utils.sheet_to_json(ws, {'{'} header: ["A","E","I","O","U","6","9"] {'}'})</b><br/>
[<br/>{aoo(XLSX.utils.sheet_to_json(ws, { header: ["A","E","I","O","U","6","9"] }))}<br/>]<br/>
</pre> );
}
```

@ -19,6 +19,8 @@ HTML format and HTML table utilities.
## HTML Table Output
**Display worksheet data in a HTML table**
```js
var html = XLSX.utils.sheet_to_html(ws, opts);
```

@ -4,25 +4,57 @@ title: Utility Functions
pagination_prev: api/write-options
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
The utility functions in this section fall into two categories:
The `sheet_to_*` functions accept a worksheet and an optional options object.
**Data Packaging**
The `*_to_sheet` functions accept a data object and an optional options object.
The "Input" functions create SheetJS data structures (worksheets or workbooks)
from rows of data or other common JS data representations
The `sheet_add_*` functions accept worksheet, data, and optional options.
These functions are paired with `write` or `writeFile` to create exports. For
example, the following diagram shows the steps to export an HTML TABLE to XLSX:
The examples are based on the following worksheet:
```mermaid
flowchart LR
html{{HTML\nTABLE}}
ws(SheetJS\nWorksheet)
wb(SheetJS\nWorkbook)
file[(workbook\nfile)]
html --> |table_to_sheet\n\n| ws
ws --> |book_new\nbook_append_sheet| wb
wb --> |writeFile\n\n| file
```
<table>
<tr><td>S</td><td>h</td><td>e</td><td>e</td><td>t</td><td>J</td><td>S</td></tr>
<tr><td>1</td><td>2</td><td> </td><td> </td><td>5</td><td>6</td><td>7</td></tr>
<tr><td>2</td><td>3</td><td> </td><td> </td><td>6</td><td>7</td><td>8</td></tr>
<tr><td>3</td><td>4</td><td> </td><td> </td><td>7</td><td>8</td><td>9</td></tr>
<tr><td>4</td><td>5</td><td>6</td><td>7</td><td>8</td><td>9</td><td>0</td></tr>
</table>
**Data Extraction**
The "Output" functions extract data from worksheets to friendlier structures.
These functions are paired with `read` or `readFile` to process data from files.
The following diagram shows the steps to generate an HTML TABLE from a URL:
```mermaid
flowchart LR
url[(Remote\nFile)]
ab[(Data\nArrayBuffer)]
wb(SheetJS\nWorkbook)
ws(SheetJS\nWorksheet)
html{{HTML\nTABLE}}
url --> |fetch\n\n| ab
ab --> |read\n\n| wb
wb --> |wb.Sheets\nselect sheet| ws
ws --> |sheet_to_html\nfirst worksheet| html
```
## Array Output
**Generate rows of data from a worksheet**
```js
var arr = XLSX.utils.sheet_to_json(ws, opts);
```
[**This functions is described in a dedicated page**](/docs/api/utilities/array#array-of-objects-input)
## Array of Arrays Input
@ -32,80 +64,13 @@ The examples are based on the following worksheet:
var ws = XLSX.utils.aoa_to_sheet(aoa, opts);
```
`XLSX.utils.aoa_to_sheet` takes an array of arrays of JS values and returns a
worksheet resembling the input data. Values are interpreted as follows:
- Numbers, Booleans and Strings are stored as the corresponding types.
- Date objects are stored as Date cells or date codes (see `cellDates` option)
- Array holes and explicit `undefined` values are skipped.
- `null` values may be stubbed (see `sheetStubs` and `nullError` options)
- Cell objects are used as-is.
The function takes an options argument:
| Option Name | Default | Description |
| :---------- | :-----: | :--------------------------------------------------- |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`cellDates` | false | Store dates as type `d` (default is `n`) |
|`sheetStubs` | false | Create cell objects of type `z` for `null` values |
|`nullError` | false | If true, emit `#NULL!` error cells for `null` values |
The example worksheet can be generated with:
```js
var ws = XLSX.utils.aoa_to_sheet([
["S", "h", "e", "e", "t", "J", "S"],
[ 1, 2, , , 5, 6, 7],
[ 2, 3, , , 6, 7, 8],
[ 3, 4, , , 7, 8, 9],
[ 4, 5, 6, 7, 8, 9, 0]
]);
```
**Add data from an array of arrays to an existing worksheet**
```js
XLSX.utils.sheet_add_aoa(ws, aoa, opts);
```
`XLSX.utils.sheet_add_aoa` takes an array of arrays of JS values and updates an
existing worksheet object. It follows the same process as `aoa_to_sheet` and
accepts an options argument:
| Option Name | Default | Description |
| :---------- | :-----: | :--------------------------------------------------- |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`cellDates` | false | Store dates as type `d` (default is `n`) |
|`sheetStubs` | false | Create cell objects of type `z` for `null` values |
|`nullError` | false | If true, emit `#NULL!` error cells for `null` values |
|`origin` | | Use specified cell as starting point (see below) |
`origin` is expected to be one of:
| `origin` | Description |
| :--------------- | :-------------------------------------------------------- |
| (cell object) | Use specified cell (cell object) |
| (string) | Use specified cell (A1-Style cell) |
| (number >= 0) | Start from the first column at specified row (0-indexed) |
| -1 | Append to bottom of worksheet starting on first column |
| (default) | Start from cell `A1` |
The example worksheet can be built up in the order `A1:G1, A2:B4, E2:G4, A5:G5`:
```js
/* Initial row */
var ws = XLSX.utils.aoa_to_sheet([ "SheetJS".split("") ]);
/* Write data starting at A2 */
XLSX.utils.sheet_add_aoa(ws, [[1,2], [2,3], [3,4]], {origin: "A2"});
/* Write data starting at E2 */
XLSX.utils.sheet_add_aoa(ws, [[5,6,7], [6,7,8], [7,8,9]], {origin:{r:1, c:4}});
/* Append row */
XLSX.utils.sheet_add_aoa(ws, [[4,5,6,7,8,9,0]], {origin: -1});
```
[**These functions are described in a dedicated page**](/docs/api/utilities/array#array-of-arrays-input)
## Array of Objects Input
@ -115,312 +80,63 @@ XLSX.utils.sheet_add_aoa(ws, [[4,5,6,7,8,9,0]], {origin: -1});
var ws = XLSX.utils.json_to_sheet(aoo, opts);
```
`XLSX.utils.json_to_sheet` takes an array of objects and returns a worksheet
with automatically-generated "headers" based on the keys of the objects. The
default column order is determined by the first appearance of the field using
`Object.keys`. The function accepts an options argument:
| Option Name | Default | Description |
| :---------- | :-----: | :--------------------------------------------------- |
|`header` | | Use specified field order (default `Object.keys`) ** |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`cellDates` | false | Store dates as type `d` (default is `n`) |
|`skipHeader` | false | If true, do not include header row in output |
|`nullError` | false | If true, emit `#NULL!` error cells for `null` values |
:::caution
All fields from each row will be written! `header` hints at a particular order
but is not exclusive. To remove fields from the export, filter the data source.
Some data sources have special options to filter properties. For example,
MongoDB will add the `_id` field when finding data from a collection:
```js
const aoo_with_id = await coll.find({}).toArray();
const ws = XLSX.utils.json_to_sheet(aoo_with_id); // includes _id column
```
This can be filtered out through the `projection` property:
```js
const aoo = await coll.find({}, {projection:{_id:0}}).toArray(); // no _id !
const ws = XLSX.utils.json_to_sheet(aoo);
```
If a data source does not provide a filter option, it can be filtered manually:
```js
const aoo = data.map(obj => Object.fromEntries(Object.entries(obj).filter(r => headers.indexOf(r[0]) > -1)));
```
:::
- If `header` is an array, missing keys will be added in order of first use.
- Cell types are deduced from the type of each value. For example, a `Date`
object will generate a Date cell, while a string will generate a Text cell.
- Null values will be skipped by default. If `nullError` is true, an error cell
corresponding to `#NULL!` will be written to the worksheet.
The example sheet cannot be reproduced using plain objects since JS object keys
must be unique. After replacing the second `e` and `S` with `e_1` and `S_1`:
```js
var ws = XLSX.utils.json_to_sheet([
{ S:1, h:2, t:5, J:6, S_1:7 },
{ S:2, h:3, t:6, J:7, S_1:8 },
{ S:3, h:4, t:7, J:8, S_1:9 },
{ S:4, h:5, e:6, e_1:7, t:8, J:9, S_1:0 },
], {header:["S","h","e","e_1","t","J","S_1"]});
```
Alternatively, a different set of unique headers can be used with `skipHeader`:
```js
var ws = XLSX.utils.json_to_sheet([
{ A: "S", B: "h", C: "e", D: "e", E: "t", F: "J", G: "S" },
{ A: 1, B: 2, E: 5, F: 6, G: 7 },
{ A: 2, B: 3, E: 6, F: 7, G: 8 },
{ A: 3, B: 4, E: 7, F: 8, G: 9 },
{ A: 4, B: 5, C: 6, D: 7, E: 8, F: 9, G: 0 },
], {header:["A","B","C","D","E","F","G"], skipHeader:true});
```
**Add data from an array of objects to an existing worksheet**
```js
XLSX.utils.sheet_add_json(ws, aoo, opts);
```
`XLSX.utils.sheet_add_json` takes an array of objects and updates an existing
worksheet object. It follows the same process as `json_to_sheet` and accepts
an options argument:
| Option Name | Default | Description |
| :---------- | :-----: | :--------------------------------------------------- |
|`header` | | Use specified column order (default `Object.keys`) |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`cellDates` | false | Store dates as type `d` (default is `n`) |
|`skipHeader` | false | If true, do not include header row in output |
|`nullError` | false | If true, emit `#NULL!` error cells for `null` values |
|`origin` | | Use specified cell as starting point (see below) |
`origin` is expected to be one of:
| `origin` | Description |
| :--------------- | :-------------------------------------------------------- |
| (cell object) | Use specified cell (cell object) |
| (string) | Use specified cell (A1-Style cell) |
| (number >= 0) | Start from the first column at specified row (0-indexed) |
| -1 | Append to bottom of worksheet starting on first column |
| (default) | Start from cell `A1` |
This example worksheet can be built up in the order `A1:G1, A2:B4, E2:G4, A5:G5`:
```js
/* Initial row */
var ws = XLSX.utils.json_to_sheet([
{ A: "S", B: "h", C: "e", D: "e", E: "t", F: "J", G: "S" }
], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true});
/* Write data starting at A2 */
XLSX.utils.sheet_add_json(ws, [
{ A: 1, B: 2 }, { A: 2, B: 3 }, { A: 3, B: 4 }
], {skipHeader: true, origin: "A2"});
/* Write data starting at E2 */
XLSX.utils.sheet_add_json(ws, [
{ A: 5, B: 6, C: 7 }, { A: 6, B: 7, C: 8 }, { A: 7, B: 8, C: 9 }
], {skipHeader: true, origin: { r: 1, c: 4 }, header: [ "A", "B", "C" ]});
/* Append row */
XLSX.utils.sheet_add_json(ws, [
{ A: 4, B: 5, C: 6, D: 7, E: 8, F: 9, G: 0 }
], {header: ["A", "B", "C", "D", "E", "F", "G"], skipHeader: true, origin: -1});
```
:::note
If the `header` option is an array, `sheet_add_json` and `sheet_to_json` will
append missing elements.
This design enables consistent header order across calls:
```jsx live
function SheetJSHeaderOrder() {
/* Use shared header */
const header = [];
const ws1 = XLSX.utils.json_to_sheet([ {C: 2, D: 3}, ], {header});
XLSX.utils.sheet_add_json(ws1, [ {D: 1, C: 4}, ], {header, origin: -1, skipHeader: true});
/* only use header in first call */
const ws2 = XLSX.utils.json_to_sheet([ {C: 2, D: 3}, ], {header:[]});
XLSX.utils.sheet_add_json(ws2, [ {D: 1, C: 4}, ], {origin: -1, skipHeader: true});
return (<pre>
<b>Objects</b>
{"\n[\n { C: 2, D: 3 },\n { D: 1, C: 4 } // different key order\n]\n"}<br/>
<b>Worksheet when same `header` array is passed to `sheet_add_json`</b>
<div dangerouslySetInnerHTML={{__html:XLSX.utils.sheet_to_html(ws1)}}/>
<i>New contents of `header`</i><br/>
{JSON.stringify(header)}<br/>
<br/>
<b>Worksheet when no `header` property is passed to `sheet_add_json`</b>
<div dangerouslySetInnerHTML={{__html:XLSX.utils.sheet_to_html(ws2)}}/>
</pre>)
}
```
:::
[**These functions are described in a dedicated page**](/docs/api/utilities/array#array-of-objects-input)
## HTML Table Input
[**This has been moved to a separate page**](/docs/api/utilities/html#html-table-input)
**Create a worksheet or workbook from a TABLE element**
### Value Override
```js
var ws = XLSX.utils.table_to_sheet(elt, opts);
var wb = XLSX.utils.table_to_book(elt, opts);
```
[**This has been moved to a separate page**](/docs/api/utilities/html#value-override)
**Add data from a TABLE element to an existing worksheet**
## Delimiter-Separated Output
```js
XLSX.utils.sheet_add_dom(ws, elt, opts);
```
[**This has been moved to a separate page**](/docs/api/utilities/csv)
[**These functions are described in a dedicated page**](/docs/api/utilities/html#html-table-input)
## HTML Output
[**This has been moved to a separate page**](/docs/api/utilities/html#html-table-output)
## Array Output
<Tabs>
<TabItem name="JS" value="JavaScript">
**Display worksheet data in a HTML table**
```js
var arr = XLSX.utils.sheet_to_json(ws, opts);
var aoa = XLSX.utils.sheet_to_json(ws, {header: 1, ...other_opts});
var html = XLSX.utils.sheet_to_html(ws, opts);
```
</TabItem>
<TabItem name="TS" value="TypeScript">
[**This function are described in a dedicated page**](/docs/api/utilities/html#html-table-output)
:::caution
## Delimiter-Separated Output
TypeScript types are purely informational. They are not included at run time
and do not influence the behavior of the `sheet_to_json` method.
**Generate CSV from a Worksheet**
**`sheet_to_json` does not perform field validation!**
:::
The main type signature treats each row as `any`:
```ts
const data: any[] = XLSX.utils.sheet_to_json(ws, opts);
```js
var csv = XLSX.utils.sheet_to_csv(ws, opts);
```
The `any[][]` overload is designed for use with `header: 1` (array of arrays):
**Export worksheet data in "UTF-16 Text" or Tab-Separated Values (TSV)**
```ts
const aoa: any[][] = XLSX.utils.sheet_to_json(ws, { header: 1, ...other_opts });
```js
var txt = XLSX.utils.sheet_to_txt(ws, opts);
```
An interface can be passed as a generic parameter. `sheet_to_json` will still
return an array of plain objects (the types do not affect runtime behavior):
```ts
interface President {
Name: string;
Index: number;
}
const data: President[] = XLSX.utils.sheet_to_json<President>(ws);
```
</TabItem>
</Tabs>
`XLSX.utils.sheet_to_json` generates an array of JS objects. The function takes
an options argument:
| Option Name | Default | Description |
| :---------- | :------: | :-------------------------------------------------- |
|`raw` | `true` | Use raw values (true) or formatted strings (false) |
|`range` | ** | Override Range (see table below) |
|`header` | | Control output format (see table below) |
|`dateNF` | FMT 14 | Use specified date format in string output |
|`defval` | | Use specified value in place of null or undefined |
|`blankrows` | ** | Include blank lines in the output ** |
- `raw` only affects cells which have a format code (`.z`) field or a formatted
text (`.w`) field.
- If `header` is specified, the first row is considered a data row; if `header`
is not specified, the first row is the header row and not considered data.
- When `header` is not specified, the conversion will automatically disambiguate
header entries by affixing `_` and a count starting at `1`. For example, if
three columns have header `foo` the output fields are `foo`, `foo_1`, `foo_2`
- `null` values are returned when `raw` is true but are skipped when false.
- If `defval` is not specified, null and undefined values are skipped normally.
If specified, all null and undefined points will be filled with `defval`
- When `header` is `1`, the default is to generate blank rows. `blankrows` must
be set to `false` to skip blank rows.
- When `header` is not `1`, the default is to skip blank rows. `blankrows` must
be true to generate blank rows
`range` is expected to be one of:
| `range` | Description |
| :--------------- | :-------------------------------------------------------- |
| (number) | Use worksheet range but set starting row to the value |
| (string) | Use specified range (A1-Style bounded range string) |
| (default) | Use worksheet range (`ws['!ref']`) |
`header` is expected to be one of:
| `header` | Description |
| :--------------- | :-------------------------------------------------------- |
| `1` | Generate an array of arrays |
| `"A"` | Row object keys are literal column labels |
| array of strings | Use specified strings as keys in row objects |
| (default) | Read and disambiguate first row as keys |
- If header is not `1`, the row object will contain the non-enumerable property
`__rowNum__` that represents the row of the sheet corresponding to the entry.
- If header is an array, the keys will not be disambiguated. This can lead to
unexpected results if the array values are not unique!
For the example worksheet:
```jsx live
function SheetJSToJSON() {
/* original data */
var ws = XLSX.utils.aoa_to_sheet([
["S", "h", "e", "e", "t", "J", "S"],
[ 1, 2, , , 5, 6, 7],
[ 2, 3, , , 6, 7, 8],
[ 3, 4, , , 7, 8, 9],
[ 4, 5, 6, 7, 8, 9, 0]
]);
/* display JS objects with some whitespace */
const aoo = o => o.map(r => " " + JSON.stringify(r).replace(/,"/g, ', "').replace(/:/g, ": ").replace(/"([A-Za-z_]\w*)":/g, '$1:')).join("\n");
const aoa = o => o.map(r => " " + JSON.stringify(r).replace(/,/g, ', ').replace(/null/g, "")).join("\n");
return ( <pre>
<b>Worksheet (as HTML)</b>
<div dangerouslySetInnerHTML={{__html: XLSX.utils.sheet_to_html(ws)}}/>
<b>XLSX.utils.sheet_to_json(ws, {'{'} header: 1 {'}'}) [array of arrays]</b><br/>
[<br/>{aoa(XLSX.utils.sheet_to_json(ws, { header: 1 }))}<br/>]<br/><br/>
<b>XLSX.utils.sheet_to_json(ws) [objects with header disambiguation]</b><br/>
[<br/>{aoo(XLSX.utils.sheet_to_json(ws))}<br/>]<br/><br/>
<b>XLSX.utils.sheet_to_json(ws, {'{'} header: "A" {'}'}) [column names as keys]</b><br/>
[<br/>{aoo(XLSX.utils.sheet_to_json(ws, { header: "A" }))}<br/>]<br/><br/>
<b>XLSX.utils.sheet_to_json(ws, {'{'} header: ["A","E","I","O","U","6","9"] {'}'})</b><br/>
[<br/>{aoo(XLSX.utils.sheet_to_json(ws, { header: ["A","E","I","O","U","6","9"] }))}<br/>]<br/>
</pre> );
}
```
[**These functions are described in a dedicated page**](/docs/api/utilities/csv)
## Formulae Output
[**This has been moved to a separate page**](/docs/api/utilities/formulae)
**Extract all formulae from a worksheet**
```js
var fmla_arr = XLSX.utils.sheet_to_formulae(ws);
```
[**This function is described in a dedicated page**](/docs/api/utilities/formulae)

@ -53,6 +53,19 @@ _Cell and cell address manipulation:_
- `encode_cell / decode_cell` converts cell addresses.
- `encode_range / decode_range` converts cell ranges.
**["Arrays of Data" section of "Utility Functions"](/docs/api/utilities/array)**
_Importing Data:_
- `aoa_to_sheet` converts an array of arrays of JS data to a worksheet.
- `json_to_sheet` converts an array of JS objects to a worksheet.
- `sheet_add_aoa` adds an array of arrays of JS data to an existing worksheet.
- `sheet_add_json` adds an array of JS objects to an existing worksheet.
_Exporting Data:_
- `sheet_to_json` converts a worksheet object to an array of JSON objects.
**["HTML" section of "Utility Functions"](/docs/api/utilities/html)**
_Reading from HTML:_
@ -85,17 +98,6 @@ _Workbook Operations:_
- `book_new` creates an empty workbook
- `book_append_sheet` adds a worksheet to a workbook
_Importing Data:_
- `aoa_to_sheet` converts an array of arrays of JS data to a worksheet.
- `json_to_sheet` converts an array of JS objects to a worksheet.
- `sheet_add_aoa` adds an array of arrays of JS data to an existing worksheet.
- `sheet_add_json` adds an array of JS objects to an existing worksheet.
_Exporting Data:_
- `sheet_to_json` converts a worksheet object to an array of JSON objects.
_Miscellaneous_
- `format_cell` generates the text value for a cell (using number formats).

@ -48,6 +48,10 @@ const config = {
googleAnalytics: {
trackingID: 'UA-36810333-1',
anonymizeIP: true
},
gtag: {
trackingID: 'G-0TSXVXRHM6',
anonymizeIP: true
}
}),
],