formula / hyperlink demos

This commit is contained in:
SheetJS 2022-05-27 10:59:53 -04:00
parent 7e0ed76f44
commit 403a102cb8
7 changed files with 654 additions and 367 deletions

@ -33,17 +33,21 @@ Cell objects are plain JS objects with keys and values following the convention:
| Key | Description |
| --- | ---------------------------------------------------------------------- |
| `v` | raw value (see [Data Types](#data-types) section for more info) |
| `w` | formatted text (if applicable) |
| | **Core Cell Properties** ([More Info](#data-types)) |
| `v` | raw value (number, string, Date object, boolean) |
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
| | **Number Formats** ([More Info](./features#number-formats)) |
| `z` | number format string associated with the cell (if requested) |
| `w` | formatted text (if applicable) |
| | **Formulae** ([More Info](./features/formulae)) |
| `f` | cell formula encoded as an A1-style string (if applicable) |
| `F` | range of enclosing array if formula is array formula (if applicable) |
| `D` | if true, array formula is dynamic (if applicable) |
| | **Other Cell Properties** ([More Info](./features)) |
| `l` | cell hyperlink and tooltip ([More Info](./features/hyperlinks)) |
| `c` | cell comments ([More Info](./features#cell-comments)) |
| `r` | rich text encoding (if applicable) |
| `h` | HTML rendering of the rich text (if applicable) |
| `c` | comments associated with the cell |
| `z` | number format string associated with the cell (if requested) |
| `l` | cell hyperlink object (`.Target` holds link, `.Tooltip` is tooltip) |
| `s` | the style/theme of the cell (if applicable) |
Built-in export utilities (such as the CSV exporter) will use the `w` text if it

@ -0,0 +1,527 @@
---
sidebar_position: 1
---
# Formulae
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<details><summary><b>Formulae File Format Support</b> (click to show)</summary>
The parser will translate from the storage representation to A1-style strings,
while the writer will translate from A1-style strings to the file format.
| Formats | Parse | Write | Array | Dynamic | Storage Representation |
|:------------------|:-----:|:-----:|:-----:|:-------:|:-----------------------|
| XLSX / XLSM | ✔ | ✔ | ✔ | ✔ | A1-style strings |
| XLSB | ✔ | | ✔ | ✔ | BIFF parsed tokens |
| XLS | ✔ | | ✔ | | BIFF parsed tokens |
| XLML | ✔ | ✔ | ✔ | | RC-style strings |
| SYLK | ✔ | ✔ | | | A1 / RC-style strings |
| CSV / TXT | ✔ | ✔ | | | A1-style strings |
| ODS / FODS / UOS | ✔ | ✔ | | | OpenFormula strings |
| WK\* | ✔ | | | | Lotus parsed tokens |
| WQ\* / WB\* / QPW | | | | | Quattro Pro tokens |
| NUMBERS | | | | | Numbers parsed tokens |
</details>
SheetJS supports reading and writing formulae for a number of file formats. When
supported, formulae will always be exported.
By default, formulae are not always imported. To ensure formula parsing, the
option `cellFormula: true` should be passed to the parser.
<Tabs>
<TabItem value="browser" label="Browser">
Typically file data will be available as an `ArrayBuffer`, either downloaded
with `fetch` / `XMLHttpRequest` or user-submitted with a File Input element.
`cellFormula: true` should be added to the second options argument:
```js
/* using read in the browser, `cellFormula` is in the second argument */
const ab = await (await fetch("test.xlsx")).arrayBuffer();
const workbook = XLSX.read(ab, { cellFormula: true });
// ------------------------------^^^^^^^^^^^^^^^^^
```
</TabItem>
<TabItem value="nodejs" label="NodeJS">
Typically file data will be available as a `Buffer` from a network request / API
or stored in the filesystem. `cellFormula: true` should be added to the second
options argument to `read` or `readFile`:
**`XLSX.read`**
```js
/* using read in NodeJS, `cellFormula` is in the second argument */
const ab = await (await fetch("test.xlsx")).arrayBuffer();
const workbook = XLSX.read(ab, { cellFormula: true });
// ------------------------------^^^^^^^^^^^^^^^^^
```
**`XLSX.readFile`**
```js
/* using readFile in NodeJS, add `cellFormula` to the second argument */
const workbook = XLSX.readFile("test.xlsx", { cellFormula: true });
// -------------------------------------------^^^^^^^^^^^^^^^^^
```
</TabItem>
<TabItem value="deno" label="Deno">
Typically file data will be available as a `Uint8Array` / `ArrayBuffer` from an
API or stored in the filesystem. `cellFormula: true` should be added to the
second options argument to `read` or `readFile`:
**`XLSX.read`**
```js
/* using read in Deno, `cellFormula` is in the second argument */
const ab = await (await fetch("test.xlsx")).arrayBuffer();
const workbook = XLSX.read(ab, { cellFormula: true });
// ------------------------------^^^^^^^^^^^^^^^^^
```
**`XLSX.readFile`**
```js
/* using readFile in Deno, add `cellFormula` to the second argument */
const workbook = XLSX.readFile("test.xlsx", { cellFormula: true });
// -------------------------------------------^^^^^^^^^^^^^^^^^
```
</TabItem>
</Tabs>
## A1-Style Formulae
The A1-style formula string is stored in the `f` field of the cell object.
Spreadsheet software typically represent formulae with a leading `=` sign, but
SheetJS formulae omit the `=`.
<details><summary><b>What is A1-style?</b> (click to show)</summary>
A1-style is the default in Excel.
Columns are specified with letters, counting from `A` to `Z`, then `AA` to `ZZ`,
then `AAA`. Some sample values, along with SheetJS column indices, are listed:
| Ordinal | A1 Name | SheetJS |
|:--------|:--------|--------:|
| First | `A` | `0` |
| Second | `B` | `1` |
| 26th | `Z` | `25` |
| 27th | `AA` | `26` |
| 702st | `ZZ` | `701` |
| 703rd | `AAA` | `702` |
| 16384th | `XFD` | `16383` |
Rows are specified with numbers, starting from `1` for the first row. SheetJS
APIs that take row indices start from `0` (ECMAScript convention).
A cell address is the concatenation of column text and row number. For example,
the cell in the third column and fourth row is "C4".
A cell range is represented as the top-left cell of the range, followed by `:`,
followed by the bottom-right cell of the range. For example, the range `"C2:D4"`
includes 6 cells marked with ▒ in the table below:
<table><tbody>
<tr><th></th><th>A</th><th>B</th><th>C</th><th>D</th><th>E</th></tr>
<tr><th>1</th><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>2</th><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>3</th><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>4</th><td></td><td></td><td></td><td></td><td></td></tr>
<tr><th>5</th><td></td><td></td><td></td><td></td><td></td></tr>
</tbody></table>
A column range is represented by the left-most column, followed by `:`, followed
by the right-most column. For example, the range `C:D` represents the third and
fourth columns.
A row range is represented by the top-most row, followed by `:`, followed by the
bottom-most column. For example, `2:4` represents the second/third/fourth rows.
</details>
For example, consider [this test file](pathname:///files/concat.xlsx):
![D1=CONCAT("Sheet", "JS")](pathname:///files/concat.png)
```jsx live
/* The live editor requires this function wrapper */
function ConcatFormula(props) {
const [text, setText] = React.useState([]);
/* Fetch and display formula */
React.useEffect(async() => {
/* Fetch file */
const ab = await (await fetch("/files/concat.xlsx")).arrayBuffer();
/* Parse file */
const wb = XLSX.read(ab, {cellFormula: true});
const ws = wb.Sheets[wb.SheetNames[0]];
/* Look at cell D1 */
const addr = "D1";
const { t, v, f } = ws[addr];
setText(`\
CELL ADDRESS: ${addr}\n\
CELL FORMULA: ${f}\n\
VALUE (TYPE): "${v}" ("${t}")\n\
`);
}, []);
return (<pre>{text}</pre>);
}
```
## Single-Cell Formulae
For simple formulae, the `f` key of the desired cell can be set to the actual
formula text. This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`:
```js
var worksheet = {
"!ref": "A1:A3", // Worksheet range A1:A3
A1: { t: "n", v: 1 }, // A1 is a number (1)
A2: { t: "n", v: 2 }, // A2 is a number (2)
A3: { t: "n", v: 3, f: "A1+A2" } // A3 =A1+A2
};
```
Utilities like `aoa_to_sheet` will accept cell objects in lieu of values:
```js
var worksheet = XLSX.utils.aoa_to_sheet([
[ 1 ], // A1
[ 2 ], // A2
[ {t: "n", v: 3, f: "A1+A2"} ] // A3
]);
```
<details open><summary><b>Live Example</b> (click to show)</summary>
```jsx live
/* The live editor requires this function wrapper */
function ExportSimpleFormula(props) {
/* Callback invoked when the button is clicked */
const xport = React.useCallback(() => {
/* Create worksheet with A1=1, A2=2, A3=A1+A2 */
var ws = XLSX.utils.aoa_to_sheet([
[ 1 ], // A1
[ 2 ], // A2
[ {t: "n", v: 3, f: "A1+A2"} ] // A3
]);
/* Export to file (start a download) */
var wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(wb, "SheetJSFormula1.xlsx");
});
return (<>
<button onClick={xport}><b>Export XLSX!</b></button>
</>);
}
```
</details>
Cells with formula entries but no value will be serialized in a way that Excel
and other spreadsheet tools will recognize. This library will not automatically
compute formula results! For example, the following worksheet will include the
`BESSELJ` function but the result will not be available in JavaScript:
```js
var worksheet = XLSX.utils.aoa_to_sheet([
[ 3.14159, 2 ], // Row "1"
[ { t: "n", f: "BESSELJ(A1,B1)" } ] // Row "2" will be calculated on file open
])
```
If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro)
offers a formula calculator component for evaluating expressions, updating
values and dependent cells, and refreshing entire workbooks.
## Array Formulae
_Assign an array formula_
```js
XLSX.utils.sheet_set_array_formula(worksheet, range, formula);
```
Array formulae are stored in the top-left cell of the array block. All cells
of an array formula have a `F` field corresponding to the range. A single-cell
formula can be distinguished from a plain formula by the presence of `F` field.
The following snippet sets cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
```js
// API function
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)");
// ... OR raw operations
worksheet["C1"] = { t: "n", f: "SUM(A1:A3*B1:B3)", F: "C1:C1" };
```
For a multi-cell array formula, every cell has the same array range but only the
first cell specifies the formula. Consider `D1:D3=A1:A3*B1:B3`:
```js
// API function
XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3");
// ... OR raw operations
worksheet["D1"] = { t: "n", F: "D1:D3", f: "A1:A3*B1:B3" };
worksheet["D2"] = { t: "n", F: "D1:D3" };
worksheet["D3"] = { t: "n", F: "D1:D3" };
```
Utilities and writers are expected to check for the presence of a `F` field and
ignore any possible formula element `f` in cells other than the starting cell.
They are not expected to perform validation of the formulae!
### Dynamic Array Formulae
_Assign a dynamic array formula_
```js
XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true);
```
Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB
file formats. They are represented like normal array formulae but have special
cell metadata indicating that the formula should be allowed to adjust the range.
An array formula can be marked as dynamic by setting the cell `D` property to
true. The `F` range is expected but can be the set to the current cell:
```js
// API function
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
// ... OR raw operations
worksheet["C1"] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic
```
## Localization
SheetJS operates at the file level. Excel stores formula expressions using the
English (United States) function names. For non-English users, Excel uses a
localized set of function names.
For example, when the computer language and region is set to Spanish, Excel
interprets `=CONTAR(A1:C3)` as if `CONTAR` is the `COUNT` function. However,
in the actual file, Excel stores `COUNT(A1:C3)`.
[JSON Translation table](https://oss.sheetjs.com/notes/fmla/table.json).
<details open><summary><b>Interactive Translator</b> (click to show)</summary>
```jsx live
/* The live editor requires this function wrapper */
function Translator(props) {
const [locales, setLocales] = React.useState([]);
const [data, setData] = React.useState({});
const [names, setNames] = React.useState([]);
const [name, setName] = React.useState("Enter a function name");
/* Fetch and display formula */
React.useEffect(async() => {
/* Fetch data */
const json = await (await fetch("https://oss.sheetjs.com/notes/fmla/table.json")).json();
setLocales(Object.keys(json));
setData(json);
setNames(json.en);
setName(json.es[0])
}, []);
const update_name = React.useCallback(() => {
const nameelt = document.getElementById("fmla");
const idx = nameelt.options[nameelt.selectedIndex].value;
const toelt = document.getElementById("tolocale");
const tovalue = toelt.options[toelt.selectedIndex].value;
setName(data[tovalue][idx]);
});
const update_from = React.useCallback(() => {
const fromelt = document.getElementById("fromlocale");
const fromvalue = fromelt.options[fromelt.selectedIndex].value;
setNames(data[fromvalue]);
});
return (<>
<b>Name: </b><select id="fmla" onChange={update_name}>
{names.map((n, idx) => (<option value={idx}>{n}</option>))}
</select><br/>
<b>From: </b><select id="fromlocale" onChange={update_from}>
{locales.map(l => (<option value={l} selected={l=="en"}>{l}</option>))}
</select>
<b> To: </b><select id="tolocale" onChange={update_name}>
{locales.map(l => (<option value={l} selected={l=="es"}>{l}</option>))}
</select><br/>
<b> Translation: </b><pre id="out">{name}</pre>
</>);
}
```
</details>
## Prefixed "Future Functions"
Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when
stored in files. When writing formula expressions using these functions, the
prefix is required for maximal compatibility:
```js
// Broadest compatibility
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
// Can cause errors in spreadsheet software
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1);
```
When reading a file, the `xlfn` option preserves the prefixes.
<details>
<summary><b> Functions requiring `_xlfn.` prefix</b> (click to show)</summary>
This list is growing with each Excel release.
```
ACOT
ACOTH
AGGREGATE
ARABIC
BASE
BETA.DIST
BETA.INV
BINOM.DIST
BINOM.DIST.RANGE
BINOM.INV
BITAND
BITLSHIFT
BITOR
BITRSHIFT
BITXOR
BYCOL
BYROW
CEILING.MATH
CEILING.PRECISE
CHISQ.DIST
CHISQ.DIST.RT
CHISQ.INV
CHISQ.INV.RT
CHISQ.TEST
COMBINA
CONFIDENCE.NORM
CONFIDENCE.T
COT
COTH
COVARIANCE.P
COVARIANCE.S
CSC
CSCH
DAYS
DECIMAL
ERF.PRECISE
ERFC.PRECISE
EXPON.DIST
F.DIST
F.DIST.RT
F.INV
F.INV.RT
F.TEST
FIELDVALUE
FILTERXML
FLOOR.MATH
FLOOR.PRECISE
FORMULATEXT
GAMMA
GAMMA.DIST
GAMMA.INV
GAMMALN.PRECISE
GAUSS
HYPGEOM.DIST
IFNA
IMCOSH
IMCOT
IMCSC
IMCSCH
IMSEC
IMSECH
IMSINH
IMTAN
ISFORMULA
ISOMITTED
ISOWEEKNUM
LAMBDA
LET
LOGNORM.DIST
LOGNORM.INV
MAKEARRAY
MAP
MODE.MULT
MODE.SNGL
MUNIT
NEGBINOM.DIST
NORM.DIST
NORM.INV
NORM.S.DIST
NORM.S.INV
NUMBERVALUE
PDURATION
PERCENTILE.EXC
PERCENTILE.INC
PERCENTRANK.EXC
PERCENTRANK.INC
PERMUTATIONA
PHI
POISSON.DIST
QUARTILE.EXC
QUARTILE.INC
QUERYSTRING
RANDARRAY
RANK.AVG
RANK.EQ
REDUCE
RRI
SCAN
SEC
SECH
SEQUENCE
SHEET
SHEETS
SKEW.P
SORTBY
STDEV.P
STDEV.S
T.DIST
T.DIST.2T
T.DIST.RT
T.INV
T.INV.2T
T.TEST
UNICHAR
UNICODE
UNIQUE
VAR.P
VAR.S
WEBSERVICE
WEIBULL.DIST
XLOOKUP
XOR
Z.TEST
```
</details>

@ -0,0 +1,100 @@
# Hyperlinks
<details>
<summary><b>Format Support</b> (click to show)</summary>
**Cell Hyperlinks**: XLSX/M, XLSB, BIFF8 XLS, XLML, ODS, HTML
**Tooltips**: XLSX/M, XLSB, BIFF8 XLS, XLML
</details>
Hyperlinks are stored in the `l` key of cell objects. The `Target` field of the
hyperlink object is the target of the link, including the URI fragment. Tooltips
are stored in the `Tooltip` field and are displayed when hovering over the text.
For example, the following snippet creates a link from cell `A3` to
<https://sheetjs.com> with the tip `"Find us @ SheetJS.com!"`:
```js
ws["A1"].l = { Target: "https://sheetjs.com", Tooltip: "Find us @ SheetJS.com!" };
```
Note that Excel does not automatically style hyperlinks. They will be displayed
using default style. <a href="https://sheetjs.com/pro">SheetJS Pro Basic</a>
extends this export with support for hyperlink styling.
## Remote Links
HTTP / HTTPS links can be used directly:
```js
ws["A2"].l = { Target: "https://docs.sheetjs.com/#hyperlinks" };
ws["A3"].l = { Target: "http://localhost:7262/yes_localhost_works" };
```
Excel also supports `mailto` email links with subject line:
```js
ws["A4"].l = { Target: "mailto:ignored@dev.null" };
ws["A5"].l = { Target: "mailto:ignored@dev.null?subject=Test Subject" };
```
## Local Links
Links to absolute paths should use the `file://` URI scheme:
```js
ws["B1"].l = { Target: "file:///SheetJS/t.xlsx" }; /* Link to /SheetJS/t.xlsx */
ws["B2"].l = { Target: "file:///c:/SheetJS.xlsx" }; /* Link to c:\SheetJS.xlsx */
```
Links to relative paths can be specified without a scheme:
```js
ws["B3"].l = { Target: "SheetJS.xlsb" }; /* Link to SheetJS.xlsb */
ws["B4"].l = { Target: "../SheetJS.xlsm" }; /* Link to ../SheetJS.xlsm */
```
Relative Paths have undefined behavior in the SpreadsheetML 2003 format. Excel
2019 will treat a `..\` parent mark as two levels up.
## Internal Links
Links where the target is a cell or range or defined name in the same workbook
("Internal Links") are marked with a leading hash character:
```js
ws["C1"].l = { Target: "#E2" }; /* Link to cell E2 */
ws["C2"].l = { Target: "#Sheet2!E2" }; /* Link to cell E2 in sheet Sheet2 */
ws["C3"].l = { Target: "#SomeDefinedName" }; /* Link to Defined Name */
```
## HTML
The HTML DOM parser will process `<a>` links in the table:
```jsx live
/* The live editor requires this function wrapper */
function ExportHyperlink(props) {
/* Callback invoked when the button is clicked */
const xport = React.useCallback(() => {
/* Create worksheet from HTML DOM TABLE */
const table = document.getElementById("TableLink");
const wb = XLSX.utils.table_to_book(table);
/* Export to file (start a download) */
XLSX.writeFile(wb, "SheetJSHyperlink1.xlsx");
});
return (<>
<button onClick={xport}><b>Export XLSX!</b></button>
<table id="TableLink"><tbody><tr><td>
Do not click here, for it is link-less.
</td></tr><tr><td>
<a href="https://sheetjs.com">Click here for more info</a>
</td></tr></tbody></table>
</>);
}
```

@ -0,0 +1,4 @@
{
"label": "Spreadsheet Features",
"position": 7
}

@ -1,7 +1,3 @@
---
sidebar_position: 7
---
# Spreadsheet Features
Even for basic features like date storage, the official Excel formats store the
@ -9,296 +5,6 @@ same content in different ways. The parsers are expected to convert from the
underlying file format representation to the Common Spreadsheet Format. Writers
are expected to convert from CSF back to the underlying file format.
## Formulae
The A1-style formula string is stored in the `f` field. Even though different
file formats store the formulae in different ways, the formats are translated.
Even though some formats store formulae with a leading equal sign, CSF formulae
do not start with `=`.
<details>
<summary><b>Formulae File Format Support</b> (click to show)</summary>
| Storage Representation | Formats | Read | Write |
|:-----------------------|:-------------------------|:-----:|:-----:|
| A1-style strings | XLSX | ✔ | ✔ |
| RC-style strings | XLML and plain text | ✔ | ✔ |
| BIFF Parsed formulae | XLSB and all XLS formats | ✔ | |
| OpenFormula formulae | ODS/FODS/UOS | ✔ | ✔ |
| Lotus Parsed formulae | All Lotus WK_ formats | ✔ | |
Since Excel prohibits named cells from colliding with names of A1 or RC style
cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed
formulae and Lotus Parsed formulae have to be explicitly unwound. OpenFormula
formulae can be converted with regular expressions.
Shared formulae are decompressed and each cell has the formula corresponding to
its cell. Writers generally do not attempt to generate shared formulae.
</details>
### Single-Cell Formulae
For simple formulae, the `f` key of the desired cell can be set to the actual
formula text. This worksheet represents `A1=1`, `A2=2`, and `A3=A1+A2`:
```js
var worksheet = {
"!ref": "A1:A3",
A1: { t:'n', v:1 },
A2: { t:'n', v:2 },
A3: { t:'n', v:3, f:'A1+A2' }
};
```
Utilities like `aoa_to_sheet` will accept cell objects in lieu of values:
```js
var worksheet = XLSX.utils.aoa_to_sheet([
[ 1 ], // A1
[ 2 ], // A2
[ {t: "n", v: 3, f: "A1+A2"} ] // A3
]);
```
Cells with formula entries but no value will be serialized in a way that Excel
and other spreadsheet tools will recognize. This library will not automatically
compute formula results! For example, the following worksheet will include the
`BESSELJ` function but the result will not be available in JavaScript:
```js
var worksheet = XLSX.utils.aoa_to_sheet([
[ 3.14159, 2 ], // Row "1"
[ { t:'n', f:'BESSELJ(A1,B1)' } ] // Row "2" will be calculated on file open
}
```
If the actual results are needed in JS, [SheetJS Pro](https://sheetjs.com/pro)
offers a formula calculator component for evaluating expressions, updating
values and dependent cells, and refreshing entire workbooks.
### Array Formulae
_Assign an array formula_
```js
XLSX.utils.sheet_set_array_formula(worksheet, range, formula);
```
Array formulae are stored in the top-left cell of the array block. All cells
of an array formula have a `F` field corresponding to the range. A single-cell
formula can be distinguished from a plain formula by the presence of `F` field.
For example, setting the cell `C1` to the array formula `{=SUM(A1:A3*B1:B3)}`:
```js
// API function
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "SUM(A1:A3*B1:B3)");
// ... OR raw operations
worksheet['C1'] = { t:'n', f: "SUM(A1:A3*B1:B3)", F:"C1:C1" };
```
For a multi-cell array formula, every cell has the same array range but only the
first cell specifies the formula. Consider `D1:D3=A1:A3*B1:B3`:
```js
// API function
XLSX.utils.sheet_set_array_formula(worksheet, "D1:D3", "A1:A3*B1:B3");
// ... OR raw operations
worksheet['D1'] = { t:'n', F:"D1:D3", f:"A1:A3*B1:B3" };
worksheet['D2'] = { t:'n', F:"D1:D3" };
worksheet['D3'] = { t:'n', F:"D1:D3" };
```
Utilities and writers are expected to check for the presence of a `F` field and
ignore any possible formula element `f` in cells other than the starting cell.
They are not expected to perform validation of the formulae!
### Dynamic Arrays
_Assign a dynamic array formula_
```js
XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true);
```
Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB
file formats. They are represented like normal array formulae but have special
cell metadata indicating that the formula should be allowed to adjust the range.
An array formula can be marked as dynamic by setting the cell's `D` property to
true. The `F` range is expected but can be the set to the current cell:
```js
// API function
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
// ... OR raw operations
worksheet['C1'] = { t: "s", f: "_xlfn.UNIQUE(A1:A3)", F:"C1", D: 1 }; // dynamic
```
### Localization
SheetJS operates at the file level. Excel stores formula expressions using the
English (United States) function names. For non-English users, Excel uses a
localized set of function names.
For example, when the computer language and region is set to French (France),
Excel interprets `=SOMME(A1:C3)` as if `SOMME` is the `SUM` function. However,
in the actual file, Excel stores `SUM(A1:C3)`.
**Prefixed "Future Functions"**
Functions introduced in newer versions of Excel are prefixed with `_xlfn.` when
stored in files. When writing formula expressions using these functions, the
prefix is required for maximal compatibility:
```js
// Broadest compatibility
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "_xlfn.UNIQUE(A1:A3)", 1);
// Can cause errors in spreadsheet software
XLSX.utils.sheet_set_array_formula(worksheet, "C1", "UNIQUE(A1:A3)", 1);
```
When reading a file, the `xlfn` option preserves the prefixes.
<details>
<summary><b> Functions requiring `_xlfn.` prefix</b> (click to show)</summary>
This list is growing with each Excel release.
```
ACOT
ACOTH
AGGREGATE
ARABIC
BASE
BETA.DIST
BETA.INV
BINOM.DIST
BINOM.DIST.RANGE
BINOM.INV
BITAND
BITLSHIFT
BITOR
BITRSHIFT
BITXOR
BYCOL
BYROW
CEILING.MATH
CEILING.PRECISE
CHISQ.DIST
CHISQ.DIST.RT
CHISQ.INV
CHISQ.INV.RT
CHISQ.TEST
COMBINA
CONFIDENCE.NORM
CONFIDENCE.T
COT
COTH
COVARIANCE.P
COVARIANCE.S
CSC
CSCH
DAYS
DECIMAL
ERF.PRECISE
ERFC.PRECISE
EXPON.DIST
F.DIST
F.DIST.RT
F.INV
F.INV.RT
F.TEST
FIELDVALUE
FILTERXML
FLOOR.MATH
FLOOR.PRECISE
FORMULATEXT
GAMMA
GAMMA.DIST
GAMMA.INV
GAMMALN.PRECISE
GAUSS
HYPGEOM.DIST
IFNA
IMCOSH
IMCOT
IMCSC
IMCSCH
IMSEC
IMSECH
IMSINH
IMTAN
ISFORMULA
ISOMITTED
ISOWEEKNUM
LAMBDA
LET
LOGNORM.DIST
LOGNORM.INV
MAKEARRAY
MAP
MODE.MULT
MODE.SNGL
MUNIT
NEGBINOM.DIST
NORM.DIST
NORM.INV
NORM.S.DIST
NORM.S.INV
NUMBERVALUE
PDURATION
PERCENTILE.EXC
PERCENTILE.INC
PERCENTRANK.EXC
PERCENTRANK.INC
PERMUTATIONA
PHI
POISSON.DIST
QUARTILE.EXC
QUARTILE.INC
QUERYSTRING
RANDARRAY
RANK.AVG
RANK.EQ
REDUCE
RRI
SCAN
SEC
SECH
SEQUENCE
SHEET
SHEETS
SKEW.P
SORTBY
STDEV.P
STDEV.S
T.DIST
T.DIST.2T
T.DIST.RT
T.INV
T.INV.2T
T.TEST
UNICHAR
UNICODE
UNIQUE
VAR.P
VAR.S
WEBSERVICE
WEIBULL.DIST
XLOOKUP
XOR
Z.TEST
```
</details>
## Row and Column Properties
<details>
@ -327,12 +33,12 @@ type ColInfo = {
/* column width is specified in one of the following ways: */
wpx?: number; // width in screen pixels
width?: number; // width in Excel's "Max Digit Width", width*256 is integral
width?: number; // width in Excel "Max Digit Width", width*256 is integral
wch?: number; // width in characters
/* other fields for preserving features from files */
level?: number; // 0-indexed outline / group level
MDW?: number; // Excel's "Max Digit Width" unit, always integral
MDW?: number; // Excel "Max Digit Width" unit, always integral
};
```
@ -447,6 +153,7 @@ var wb = {
}
}
```
</details>
The rules are slightly different from how Excel displays custom number formats.
@ -500,80 +207,18 @@ is not always the case over the Internet. To get around this ambiguity, parse
functions accept the `dateNF` option to override the interpretation of that
specific format string.
## Hyperlinks
## Cell Comments
<details>
<summary><b>Format Support</b> (click to show)</summary>
**Cell Hyperlinks**: XLSX/M, XLSB, BIFF8 XLS, XLML, ODS
**Simple Notes/Comments**: XLSX/M, XLSB, BIFF8 XLS (read only), XLML, ODS (read only)
**Tooltips**: XLSX/M, XLSB, BIFF8 XLS, XLML
**Threaded Comments**: XLSX/M, XLSB (read only)
</details>
Hyperlinks are stored in the `l` key of cell objects. The `Target` field of the
hyperlink object is the target of the link, including the URI fragment. Tooltips
are stored in the `Tooltip` field and are displayed when you move your mouse
over the text.
For example, the following snippet creates a link from cell `A3` to
<https://sheetjs.com> with the tip `"Find us @ SheetJS.com!"`:
```js
ws['A1'].l = { Target:"https://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" };
```
Note that Excel does not automatically style hyperlinks -- they will generally
be displayed as normal text.
_Remote Links_
HTTP / HTTPS links can be used directly:
```js
ws['A2'].l = { Target:"https://docs.sheetjs.com/#hyperlinks" };
ws['A3'].l = { Target:"http://localhost:7262/yes_localhost_works" };
```
Excel also supports `mailto` email links with subject line:
```js
ws['A4'].l = { Target:"mailto:ignored@dev.null" };
ws['A5'].l = { Target:"mailto:ignored@dev.null?subject=Test Subject" };
```
_Local Links_
Links to absolute paths should use the `file://` URI scheme:
```js
ws['B1'].l = { Target:"file:///SheetJS/t.xlsx" }; /* Link to /SheetJS/t.xlsx */
ws['B2'].l = { Target:"file:///c:/SheetJS.xlsx" }; /* Link to c:\SheetJS.xlsx */
```
Links to relative paths can be specified without a scheme:
```js
ws['B3'].l = { Target:"SheetJS.xlsb" }; /* Link to SheetJS.xlsb */
ws['B4'].l = { Target:"../SheetJS.xlsm" }; /* Link to ../SheetJS.xlsm */
```
Relative Paths have undefined behavior in the SpreadsheetML 2003 format. Excel
2019 will treat a `..\` parent mark as two levels up.
_Internal Links_
Links where the target is a cell or range or defined name in the same workbook
("Internal Links") are marked with a leading hash character:
```js
ws['C1'].l = { Target:"#E2" }; /* Link to cell E2 */
ws['C2'].l = { Target:"#Sheet2!E2" }; /* Link to cell E2 in sheet Sheet2 */
ws['C3'].l = { Target:"#SomeDefinedName" }; /* Link to Defined Name */
```
## Cell Comments
Cell comments are objects stored in the `c` array of cell objects. The actual
contents of the comment are split into blocks based on the comment author. The
`a` field of each comment object is the author of the comment and the `t` field
@ -713,6 +358,13 @@ function Visibility(props) {
## VBA and Macros
<details>
<summary><b>Format Support</b> (click to show)</summary>
**VBA Modules**: XLSM, XLSB, BIFF8 XLS
</details>
VBA Macros are stored in a special data blob that is exposed in the `vbaraw`
property of the workbook object when the `bookVBA` option is `true`. They are
supported in `XLSM`, `XLSB`, and `BIFF8 XLS` formats. The supported format

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.