Added Test Data to docs site

This commit is contained in:
SheetJS 2024-04-26 00:16:13 -04:00
parent 671729b289
commit b503ebc14d
134 changed files with 2901 additions and 461 deletions

@ -123,6 +123,7 @@ This demo was last tested in the following deployments:
|:-------------|:--------|:-----------|
| `darwin-x64` | `1.1.4` | 2024-04-19 |
| `win10-x64` | `1.1.4` | 2024-04-19 |
| `linux-x64` | `1.1.4` | 2024-04-25 |
:::
@ -158,7 +159,7 @@ import * as fs from 'fs';
XLSX.set_fs(fs);
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */

@ -43,14 +43,14 @@ sequenceDiagram
## Acquire Data
The raw data is available in JSON form[^1]. It has been mirrored at
https://sheetjs.com/data/executive.json
https://docs.sheetjs.com/executive.json
### Raw Data
Acquiring the data is straightforward with `fetch`:
```js
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
```
@ -555,7 +555,7 @@ browser should try to create `Presidents.xlsx`
```jsx live
function Presidents() { return ( <button onClick={async () => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */
@ -603,7 +603,7 @@ Save the following script to `SheetJSStandaloneDemo.html`:
<script>
(async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
\n\
/* filter for the Presidents */
@ -677,7 +677,7 @@ const XLSX = require("xlsx");
(async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */
@ -755,7 +755,7 @@ const axios = require("axios");
(async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
// highlight-next-line
const raw_data = (await axios(url, {responseType: "json"})).data;
@ -814,7 +814,7 @@ Save the following script to `SheetJSDeno.ts`:
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs';
\n\
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
\n\
/* filter for the Presidents */
@ -871,7 +871,7 @@ Save the following script to `SheetJSNW.html`:
<script>
(async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
\n\
/* filter for the Presidents */
@ -978,7 +978,7 @@ import RNBU from 'react-native-blob-util';
const make_workbook = async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */

@ -41,7 +41,7 @@ sequenceDiagram
## Download File
The raw data is available in a XLS workbook[^1]. It has been mirrored at
https://sheetjs.com/data/PortfolioSummary.xls
https://docs.sheetjs.com/PortfolioSummary.xls
:::info pass
@ -55,7 +55,7 @@ data is not lost in the sands of time.
Downloading the file is straightforward with `fetch`:
```js
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const file = await (await fetch(url)).arrayBuffer();
```
@ -180,7 +180,7 @@ function SheetJSheetNames() {
const [names, setNames] = React.useState([]);
React.useEffect(() => { (async() =>{
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const file = await (await fetch(url)).arrayBuffer();
const workbook = XLSX.read(file);
/* display sheet names */
@ -228,7 +228,7 @@ function SheetJSHTMLView() {
const [__html, setHTML] = React.useState("");
React.useEffect(() => { (async() =>{
/* parse workbook, limiting to 20 rows */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer(), {sheetRows:20});
/* get first worksheet */
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
@ -247,7 +247,7 @@ The key points from looking at the table are:
- The data starts on row 7
- Rows 5 and 6 are the header rows, with merged cells for common titles
- For yearly data (2007-2012), columns A and B are merged
- For quarterly data (2013Q1 - 2023Q2), column A stores the year. Cells may be
- For quarterly data (2013Q1 and later), column A stores the year. Cells may be
merged vertically to span 4 quarters
## Extract Data
@ -315,7 +315,7 @@ function SheetJSAoAHoles() {
const [rows, setRows] = React.useState([]);
React.useEffect(() => { (async() =>{
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
/* get first worksheet */
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
@ -466,7 +466,7 @@ function SheetJSAoAFilled() {
const [rows, setRows] = React.useState([]);
React.useEffect(() => { (async() =>{
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
/* get first worksheet */
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
@ -488,11 +488,20 @@ function SheetJSAoAFilled() {
### Select Data Rows
At this point, every data row will have the year in column `A`. Since this year
is between 2007 and 2023, `Array#filter` can be used to select the rows:
At this point, each data row will have the year in column `A` and dollar value
in column `C`. The year will be between 2007 and 2024 and the value will be
positive. The following function tests a data row:
```js
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
const is_valid_row = r =>
r[0] >= 2007 && r[0] <= 2024 // year (column A) is between 2007 and 2024
&& r[2] > 0; // dollar value (column C) is positive
```
`Array#filter`, using the previous test, can select the matching rows:
```js
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
```
<details>
@ -503,7 +512,7 @@ function SheetJSAoAFiltered() {
const [rows, setRows] = React.useState([]);
React.useEffect(() => { (async() =>{
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
/* get first worksheet */
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
@ -512,7 +521,7 @@ function SheetJSAoAFiltered() {
var last_year = 0;
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
/* select data rows */
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
/* display data */
setRows(rows);
})(); }, []);
@ -579,7 +588,7 @@ function SheetJSObjects() {
const [rows, setRows] = React.useState([]);
React.useEffect(() => { (async() =>{
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
/* get first worksheet */
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
@ -588,7 +597,7 @@ function SheetJSObjects() {
var last_year = 0;
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
/* select data rows */
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
/* generate row objects */
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
/* display data */
@ -684,7 +693,7 @@ function StudentAidTotal() {
const [num, setNum] = React.useState(5);
React.useEffect(() => { (async() =>{
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
/* get first worksheet */
@ -696,7 +705,7 @@ function StudentAidTotal() {
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
/* select data rows */
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
/* generate row objects */
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
@ -739,7 +748,7 @@ Save the following script to `SheetJSStandaloneDemo.html`:
<script>
(async() => {
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
\n\
/* get first worksheet */
@ -751,7 +760,7 @@ Save the following script to `SheetJSStandaloneDemo.html`:
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
\n\
/* select data rows */
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
\n\
/* generate row objects */
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
@ -805,7 +814,7 @@ Save the following script to `SheetJSNodeJS.js`:
const XLSX = require("xlsx");
(async() => {
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
/* get first worksheet */
@ -817,7 +826,7 @@ const XLSX = require("xlsx");
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
/* select data rows */
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
/* generate row objects */
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
@ -878,7 +887,7 @@ Save the following script to `SheetJSNW.html`:
<script>
(async() => {
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
\n\
/* get first worksheet */
@ -890,7 +899,7 @@ Save the following script to `SheetJSNW.html`:
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
\n\
/* select data rows */
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
\n\
/* generate row objects */
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
@ -979,7 +988,7 @@ const App = () => {
const [rows, setRows] = React.useState([]);
React.useEffect(() => { (async() =>{
/* parse workbook */
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
const workbook = read(await (await fetch(url)).arrayBuffer());
/* get first worksheet */
@ -991,7 +1000,7 @@ const App = () => {
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
/* select data rows */
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
/* generate row objects */
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));

@ -19,7 +19,7 @@ This demo covers details elided in the official DanfoJS documentation.
:::note Tested Deployments
This example was last tested on 2024 January 03 against DanfoJS 1.1.2.
This example was last tested on 2024 April 25 against DanfoJS 1.1.2.
:::
@ -114,7 +114,7 @@ const first_three_rows = await dfd.readExcel(url, { parsingOptions: {
#### URL source
The following example fetches a [test file](https://sheetjs.com/pres.xlsx),
The following example fetches a [test file](https://docs.sheetjs.com/pres.xlsx),
parses with SheetJS and generates a DanfoJS dataframe.
```jsx live
@ -122,7 +122,7 @@ function DanfoReadExcelURL() {
const [text, setText] = React.useState("");
React.useEffect(() => { (async() => {
if(typeof dfd === "undefined") return setText("RELOAD THIS PAGE!");
const df = await dfd.readExcel("https://sheetjs.com/pres.xlsx");
const df = await dfd.readExcel("https://docs.sheetjs.com/pres.xlsx");
setText("" + df.head());
})(); }, []);
return (<pre>{text}</pre>);

@ -90,7 +90,7 @@ function worksheet_to_csv_url(worksheet) {
### CSV Demo
This demo shows a simple model fitting using the "cars" dataset from TensorFlow.
The [sample XLS file](https://sheetjs.com/data/cd.xls) contains the data. The
The [sample XLS file](https://docs.sheetjs.com/cd.xls) contains the data. The
data processing mirrors the official "Making Predictions from 2D Data" demo[^3].
```mermaid
@ -118,7 +118,7 @@ flowchart LR
The demo builds a model for predicting MPG from Horsepower data. It:
- fetches https://sheetjs.com/data/cd.xls
- fetches https://docs.sheetjs.com/cd.xls
- parses the data with the SheetJS `read`[^4] method
- selects the first worksheet[^5] and converts to CSV using `sheet_to_csv`[^6]
- generates a blob URL from the CSV text
@ -172,7 +172,7 @@ function SheetJSToTFJSCSV() {
setResults([]); setOutput(""); setDisabled(true);
try {
/* fetch file */
const f = await fetch("https://sheetjs.com/data/cd.xls");
const f = await fetch("https://docs.sheetjs.com/cd.xls");
const ab = await f.arrayBuffer();
/* parse file and get first worksheet */
const wb = XLSX.read(ab);
@ -256,7 +256,7 @@ loads data from a JSON file:
]
```
In real use cases, data is stored in [spreadsheets](https://sheetjs.com/data/cd.xls)
In real use cases, data is stored in [spreadsheets](https://docs.sheetjs.com/cd.xls)
![cd.xls screenshot](pathname:///files/cd.png)
@ -273,7 +273,7 @@ Differences from the official example are highlighted below:
async function getData() {
// highlight-start
/* fetch file */
const carsDataResponse = await fetch('https://sheetjs.com/data/cd.xls');
const carsDataResponse = await fetch('https://docs.sheetjs.com/cd.xls');
/* get file data (ArrayBuffer) */
const carsDataAB = await carsDataResponse.arrayBuffer();
/* parse */
@ -429,7 +429,7 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa);
[^1]: See [`tf.data.csv`](https://js.tensorflow.org/api/latest/#data.csv) in the TensorFlow.js documentation
[^2]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
[^3]: The ["Making Predictions from 2D Data" example](https://codelabs.developers.google.com/codelabs/tfjs-training-regression/) uses a hosted JSON file. The [sample XLS file](https://sheetjs.com/data/cd.xls) includes the same data.
[^3]: The ["Making Predictions from 2D Data" example](https://codelabs.developers.google.com/codelabs/tfjs-training-regression/) uses a hosted JSON file. The [sample XLS file](https://docs.sheetjs.com/cd.xls) includes the same data.
[^4]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^5]: See ["Workbook Object"](/docs/csf/book)
[^6]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)

@ -378,12 +378,12 @@ curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
4) Download the following test scripts and files:
- [`pres.numbers` test file](https://sheetjs.com/pres.numbers)
- [`pres.numbers` test file](https://docs.sheetjs.com/pres.numbers)
- [`sheetjs.py` script](pathname:///pandas/sheetjs.py)
- [`SheetJSPandas.py` script](pathname:///pandas/SheetJSPandas.py)
```bash
curl -LO https://sheetjs.com/pres.numbers
curl -LO https://docs.sheetjs.com/pres.numbers
curl -LO https://docs.sheetjs.com/pandas/sheetjs.py
curl -LO https://docs.sheetjs.com/pandas/SheetJSPandas.py
```

@ -61,9 +61,9 @@ 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:
The example [presidents sheet](https://docs.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>
@ -165,8 +165,8 @@ import { read, utils } from 'xlsx';
/* Fetch and update the state once */
useEffect(() => { (async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
// highlight-start
@ -192,8 +192,8 @@ import { read, utils } from 'xlsx';
/* Fetch and update the state once */
useEffect(() => { (async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
// highlight-start
@ -295,7 +295,7 @@ export default function SheetJSKaiokenAoO() {
/* Fetch and update the state once */
useEffect(() => { (async() => {
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
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<President>(ws); // generate objects
@ -412,7 +412,7 @@ and test the page.
</TabItem>
</Tabs>
When the page loads, the app will fetch https://sheetjs.com/pres.xlsx and
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
display the data from the first worksheet in a TABLE. The "Export XLSX" button
will generate a workbook that can be opened in a spreadsheet editor.
@ -443,7 +443,7 @@ export default function SheetJSKaiokenHTML() {
/* Fetch and update the state once */
useEffect(() => { (async() => {
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
const wb = read(f); // parse the array buffer
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
// highlight-start
@ -559,7 +559,7 @@ and test the page.
</TabItem>
</Tabs>
When the page loads, the app will fetch https://sheetjs.com/pres.xlsx and
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
display the data from the first worksheet in a TABLE. The "Export XLSX" button
will generate a workbook that can be opened in a spreadsheet editor.

@ -57,9 +57,9 @@ 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:
The example [presidents sheet](https://docs.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>
@ -161,8 +161,8 @@ import { read, utils } from 'xlsx';
/* Fetch and update the state once */
useEffect(() => { (async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
// highlight-start
@ -188,8 +188,8 @@ import { read, utils } from 'xlsx';
/* Fetch and update the state once */
useEffect(() => { (async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
// highlight-start
@ -286,7 +286,7 @@ export default function SheetJSReactAoO() {
/* Fetch and update the state once */
useEffect(() => { (async() => {
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
const f = await (await fetch("https://docs.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
@ -544,7 +544,7 @@ and test the page.
</TabItem>
</Tabs>
When the page loads, the app will fetch https://sheetjs.com/pres.xlsx and
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
display the data from the first worksheet in a TABLE. The "Export XLSX" button
will generate a workbook that can be opened in a spreadsheet editor.
@ -577,7 +577,7 @@ export default function SheetJSReactHTML() {
/* Fetch and update the state once */
useEffect(() => { (async() => {
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
const wb = read(f); // parse the array buffer
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
// highlight-start
@ -713,7 +713,7 @@ and test the page.
</TabItem>
</Tabs>
When the page loads, the app will fetch https://sheetjs.com/pres.xlsx and
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
display the data from the first worksheet in a TABLE. The "Export XLSX" button
will generate a workbook that can be opened in a spreadsheet editor.

@ -87,9 +87,9 @@ 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:
The example [presidents sheet](https://docs.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>
@ -184,8 +184,8 @@ interface President { Name: string; Index: number };
export class AppComponent {
rows: President[] = [ { Name: "SheetJS", Index: 0 }];
ngOnInit(): void { (async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
// highlight-start
@ -331,8 +331,8 @@ export class AppComponent {
// highlight-next-line
rows: President[] = [ { Name: "SheetJS", Index: 0 }];
ngOnInit(): void { (async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
/* parse workbook */
@ -389,8 +389,8 @@ export class AppComponent {
// highlight-next-line
rows: President[] = [ { Name: "SheetJS", Index: 0 }];
ngOnInit(): void { (async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
/* parse workbook */
@ -536,8 +536,8 @@ export class AppComponent {
@ViewChild('tableau') tabeller!: ElementRef<HTMLDivElement>;
// highlight-end
ngOnInit(): void { (async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
/* parse workbook */
@ -583,8 +583,8 @@ export class AppComponent {
@ViewChild('tableau') tabeller!: ElementRef<HTMLDivElement>;
// highlight-end
ngOnInit(): void { (async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
/* parse workbook */

@ -56,9 +56,9 @@ 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:
The example [presidents sheet](https://docs.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>
@ -170,8 +170,8 @@ const pres = ref([]);
/* Fetch and update the state once */
onMounted(async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
// highlight-start
@ -207,8 +207,8 @@ const pres = ref<President[]>([]);
/* Fetch and update the state once */
onMounted(async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
// highlight-start
@ -315,8 +315,8 @@ import { read, utils, writeFileXLSX } from 'xlsx';
const rows = ref([]);
onMounted(async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
/* parse workbook */
@ -484,8 +484,8 @@ const html = ref("");
const tableau = ref();
onMounted(async() => {
/* Download from https://sheetjs.com/pres.numbers */
const f = await fetch("https://sheetjs.com/pres.numbers");
/* Download from https://docs.sheetjs.com/pres.numbers */
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await f.arrayBuffer();
/* parse workbook */

@ -50,8 +50,8 @@ 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. For example, "Name"
and "Index" are used in [`pres.xlsx`](https://docs.sheetjs.com/pres.xlsx):
![`pres.xlsx` data](pathname:///pres.png)
@ -65,7 +65,7 @@ interface President {
Index: number;
}
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
const wb = read(f);
const data = utils.sheet_to_json<President>(wb.Sheets[wb.SheetNames[0]]);
console.log(data);
@ -96,7 +96,7 @@ let pres = [];
/* Fetch and update the state once */
onMount(async() => {
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
const wb = read(f); // parse the array buffer
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
// highlight-start
@ -202,7 +202,7 @@ let tbl;
/* Fetch and update the state once */
onMount(async() => {
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
const wb = read(f); // parse the array buffer
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
// highlight-start

@ -73,17 +73,17 @@ property to `"arraybuffer"` ensures the result is an `ArrayBuffer` object.
The SheetJS [`read`](/docs/api/parse-options) method can parse the `ArrayBuffer`
and return a SheetJS workbook object[^2].
The following controller fetches [a sample file](https://sheetjs.com/pres.xlsx),
This controller fetches [a sample file](https://docs.sheetjs.com/pres.xlsx),
parses the result into a workbook, extracts the first worksheet, and uses the
SheetJS [`sheet_to_html`](/docs/api/utilities/html#html-table-output) method to
generate a HTML table:
```js
```js title="Sample Controller"
/* The controller function must accept a `$http` argument */
app.controller('sheetjs', function($scope, $http) {
/* fetch https://sheetjs.com/pres.xlsx */
/* fetch https://docs.sheetjs.com/pres.xlsx */
$http({
method:'GET', url:'https://sheetjs.com/pres.xlsx',
method:'GET', url:'https://docs.sheetjs.com/pres.xlsx',
/* ensure the result is an ArrayBuffer object */
responseType:'arraybuffer'
}).then(function(data) {
@ -167,9 +167,9 @@ depends on the application.
### Array of Objects
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:
The example [presidents sheet](https://docs.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>
@ -198,7 +198,7 @@ file, generates row objects, and stores the array in the state:
```js
app.controller('sheetjs', function($scope, $http) {
$http({
url:'https://sheetjs.com/pres.xlsx',
url:'https://docs.sheetjs.com/pres.xlsx',
method:'GET', responseType:'arraybuffer'
}).then(function(data) {
var wb = XLSX.read(data.data);
@ -275,7 +275,7 @@ app.controller('sheetjs', function($scope, $http) {
XLSX.writeFile(wb, "SheetJSAngularJSAoO.xlsx");
};
$http({
url:'https://sheetjs.com/pres.xlsx',
url:'https://docs.sheetjs.com/pres.xlsx',
method:'GET', responseType:'arraybuffer'
}).then(function(data) {
var wb = XLSX.read(data.data);
@ -315,7 +315,7 @@ requires the `ngSanitize` plugin[^4].
var app = angular.module('s5s', ['ngSanitize']);
app.controller('sheetjs', function($scope, $http) {
$http({
url:'https://sheetjs.com/pres.xlsx',
url:'https://docs.sheetjs.com/pres.xlsx',
method:'GET', responseType:'arraybuffer'
}).then(function(data) {
var wb = XLSX.read(data.data);
@ -371,7 +371,7 @@ app.controller('sheetjs', function($scope, $http) {
XLSX.writeFile(wb, "SheetJSAngularJSHTML.xlsx");
};
$http({
url:'https://sheetjs.com/pres.xlsx',
url:'https://docs.sheetjs.com/pres.xlsx',
method:'GET', responseType:'arraybuffer'
}).then(function(data) {
var wb = XLSX.read(data.data);

@ -99,7 +99,7 @@ The following example generates a HTML table from the first worksheet:
<div id="tbl"></div>
<script>
require(["dojo/request/xhr", "xlsx"], function(xhr, _XLSX) {
xhr("https://sheetjs.com/pres.numbers", {
xhr("https://docs.sheetjs.com/pres.numbers", {
headers: { "X-Requested-With": null },
// highlight-next-line
handleAs: "arraybuffer"
@ -155,7 +155,7 @@ require([
], function(ready, xhr, Memory, registry, _XLSX) {
ready(function() {
/* fetch test file */
xhr("https://sheetjs.com/pres.xlsx", {
xhr("https://docs.sheetjs.com/pres.xlsx", {
headers: { "X-Requested-With": null },
handleAs: "arraybuffer"
}).then(function(ab) {

@ -98,7 +98,7 @@ interface President {
async function xport() {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data: President[] = await (await fetch(url)).json();
/* filter for the Presidents */

@ -167,7 +167,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("xport").addEventListener("click", function() {
/* fetch JSON data and parse */
var url = "https://sheetjs.com/data/executive.json";
var url = "https://docs.sheetjs.com/executive.json";
fetch(url).then(function(res) { return res.json(); }).then(function(raw_data) {
/* filter for the Presidents */

@ -105,7 +105,7 @@ const { utils, version, writeFileXLSX } = require('xlsx');
document.getElementById("xport").addEventListener("click", function() {
/* fetch JSON data and parse */
var url = "https://sheetjs.com/data/executive.json";
var url = "https://docs.sheetjs.com/executive.json";
fetch(url).then(function(res) { return res.json(); }).then(function(raw_data) {
/* filter for the Presidents */

@ -162,7 +162,7 @@ example, the following script corresponds to RequireJS `2.1.22`:
require(["xlsx"], function(XLSX) {
document.getElementById("xport").addEventListener("click", function() {
/* fetch JSON data and parse */
var url = "https://sheetjs.com/data/executive.json";
var url = "https://docs.sheetjs.com/executive.json";
fetch(url).then(function(res) { return res.json(); }).then(function(raw_data) {
/* filter for the Presidents */

@ -111,7 +111,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("xport").addEventListener("click", async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */

@ -86,7 +86,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("vers").innerText = version;
document.getElementById("xport").onclick = async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */
@ -146,7 +146,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("vers").innerText = version;
document.getElementById("xport").onclick = async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */

@ -121,7 +121,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("xport").addEventListener("click", async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */

@ -102,7 +102,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("xport").addEventListener("click", async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */
@ -232,7 +232,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("xport").addEventListener("click", async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/executive.json";
const url = "https://docs.sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */

@ -62,7 +62,7 @@ flowchart LR
```js
/* download data into an ArrayBuffer object */
const res = await fetch("https://sheetjs.com/pres.numbers");
const res = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await res.arrayBuffer(); // recover data as ArrayBuffer
/* parse file */
@ -71,10 +71,9 @@ const wb = XLSX.read(ab);
## Browser Demos
When the page is accessed, the browser will attempt to download https://sheetjs.com/pres.numbers
and read the workbook. The old table will be replaced with a table whose
contents match the first worksheet. The table is generated using the SheetJS
`sheet_to_html` method[^2]
When the page is accessed, https://docs.sheetjs.com/pres.numbers will be fetched
and parsed. The old table will be replaced with a table whose contents match the
first worksheet. The SheetJS `sheet_to_html` method[^2] creates the HTML table.
:::note Tested Deployments
@ -111,7 +110,7 @@ req.send();
<details>
<summary><b>Live Download demo</b> (click to show)</summary>
This demo uses `XMLHttpRequest` to download https://sheetjs.com/pres.numbers
This demo uses `XMLHttpRequest` to fetch https://docs.sheetjs.com/pres.numbers
and show the data in an HTML table.
```jsx live
@ -122,7 +121,7 @@ function SheetJSXHRDL() {
React.useEffect(() => { (async() => {
/* Fetch file */
const req = new XMLHttpRequest();
req.open("GET", "https://sheetjs.com/pres.numbers", true);
req.open("GET", "https://docs.sheetjs.com/pres.numbers", true);
req.responseType = "arraybuffer";
req.onload = e => {
/* Parse file */
@ -164,8 +163,8 @@ fetch(url).then(function(res) {
<details>
<summary><b>Live Download demo</b> (click to show)</summary>
This demo uses `fetch` to download https://sheetjs.com/pres.numbers and show
the data in an HTML table.
This demo uses `fetch` to download https://docs.sheetjs.com/pres.numbers and
show the data in an HTML table.
```jsx live
function SheetJSFetchDL() {
@ -174,7 +173,7 @@ function SheetJSFetchDL() {
/* Fetch and update HTML */
React.useEffect(() => { (async() => {
/* Fetch file */
const res = await fetch("https://sheetjs.com/pres.numbers");
const res = await fetch("https://docs.sheetjs.com/pres.numbers");
const ab = await res.arrayBuffer();
/* Parse file */
@ -209,7 +208,7 @@ In a GET request, the default behavior is to return a `Blob` object. Passing
```js
$.ajax({
type: "GET", url: "https://sheetjs.com/pres.numbers",
type: "GET", url: "https://docs.sheetjs.com/pres.numbers",
/* suppress jQuery post-processing */
// highlight-next-line
@ -259,8 +258,8 @@ async function workbook_dl_axios(url) {
<details>
<summary><b>Live Download demo</b> (click to show)</summary>
This demo uses `axios` to download https://sheetjs.com/pres.numbers and show
the data in an HTML table.
This demo uses `axios` to download https://docs.sheetjs.com/pres.numbers and
show the data in an HTML table.
:::caution pass
@ -282,7 +281,7 @@ function SheetJSAxiosDL() {
React.useEffect(() => { (async() => {
if(typeof axios != "function") return setHTML("ReferenceError: axios is not defined");
/* Fetch file */
const res = await axios("https://sheetjs.com/pres.numbers", {responseType: "arraybuffer"});
const res = await axios("https://docs.sheetjs.com/pres.numbers", {responseType: "arraybuffer"});
/* Parse file */
const wb = XLSX.read(res.data);
@ -321,8 +320,8 @@ superagent
<details>
<summary><b>Live Download demo</b> (click to show)</summary>
This demo uses `superagent` to download https://sheetjs.com/pres.numbers and
show the data in an HTML table.
This demo uses `superagent` to download https://docs.sheetjs.com/pres.numbers
and show the data in an HTML table.
:::caution pass
@ -346,7 +345,7 @@ function SheetJSSuperAgentDL() {
return setHTML("ReferenceError: superagent is not defined");
/* Fetch file */
superagent
.get("https://sheetjs.com/pres.numbers")
.get("https://docs.sheetjs.com/pres.numbers")
.responseType("arraybuffer")
.end((err, res) => {
/* Parse file */
@ -375,7 +374,7 @@ The `https` module provides a low-level `get` method for HTTPS GET requests:
```js title="SheetJSHTTPSGet.js"
var https = require("https"), XLSX = require("xlsx");
https.get('https://sheetjs.com/pres.numbers', function(res) {
https.get('https://docs.sheetjs.com/pres.numbers', function(res) {
var bufs = [];
res.on('data', function(chunk) { bufs.push(chunk); });
res.on('end', function() {
@ -465,7 +464,7 @@ async function parse_from_url(url) {
}
(async() => {
const wb = await parse_from_url('https://sheetjs.com/pres.numbers');
const wb = await parse_from_url('https://docs.sheetjs.com/pres.numbers');
/* print the first worksheet to console */
var ws = wb.Sheets[wb.SheetNames[0]];
console.log(XLSX.utils.sheet_to_csv(ws));
@ -499,7 +498,7 @@ Setting the option `encoding: null` passes raw buffers:
```js title="SheetJSRequest.js"
var XLSX = require('xlsx'), request = require('request');
var url = 'https://sheetjs.com/pres.numbers';
var url = 'https://docs.sheetjs.com/pres.numbers';
/* call `request` with the option `encoding: null` */
// highlight-next-line
@ -587,7 +586,7 @@ async function workbook_dl_axios(url) {
}
(async() => {
const wb = await workbook_dl_axios('https://sheetjs.com/pres.numbers');
const wb = await workbook_dl_axios('https://docs.sheetjs.com/pres.numbers');
/* print the first worksheet to console */
var ws = wb.Sheets[wb.SheetNames[0]];
console.log(XLSX.utils.sheet_to_csv(ws));

@ -151,11 +151,11 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz express
node SheetJSExpressCSV.js
```
4) Test POST requests using https://sheetjs.com/pres.numbers . The following
commands should be run in a new terminal window:
4) Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands
should be run in a new terminal window:
```bash
curl -LO https://sheetjs.com/pres.numbers
curl -LO https://docs.sheetjs.com/pres.numbers
curl -X POST -F upload=@pres.numbers http://localhost:3000/upload
```

@ -123,7 +123,7 @@ curl -LO https://docs.sheetjs.com/drash/SheetJSDrash.ts
deno run --allow-net SheetJSDrash.ts
```
3) Download the test file https://sheetjs.com/pres.numbers
3) Download the test file https://docs.sheetjs.com/pres.numbers
4) Open `http://localhost:7262/` in your browser.

@ -151,11 +151,11 @@ app.listen(3000);
bun run src/SheetJSElysia.ts
```
5) Test POST requests using https://sheetjs.com/pres.numbers . The following
commands should be run in a new terminal window:
5) Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands
should be run in a new terminal window:
```bash
curl -LO https://sheetjs.com/pres.numbers
curl -LO https://docs.sheetjs.com/pres.numbers
curl -X POST -F upload=@pres.numbers http://localhost:3000/
```

@ -209,11 +209,11 @@ npx @nestjs/cli start
:::
8) Test POST requests using https://sheetjs.com/pres.numbers . The following
commands should be run in a new terminal window:
8) Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands
should be run in a new terminal window:
```bash
curl -LO https://sheetjs.com/pres.numbers
curl -LO https://docs.sheetjs.com/pres.numbers
curl -X POST -F upload=@pres.numbers http://localhost:3000/sheetjs/upload
```

@ -166,11 +166,11 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz fastify
node SheetJSFastify.js
```
3) Test POST requests using https://sheetjs.com/pres.numbers . The following
commands should be run in a new terminal window:
3) Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands
should be run in a new terminal window:
```bash
curl -LO https://sheetjs.com/pres.numbers
curl -LO https://docs.sheetjs.com/pres.numbers
curl -X POST -F upload=@pres.numbers http://localhost:3000/
```

@ -230,11 +230,11 @@ node main.mjs
Keep the server process running during the test.
6) Test with the [`pres.numbers` sample file](https://sheetjs.com/pres.numbers).
6) Test with the [`pres.numbers` sample file](https://docs.sheetjs.com/pres.numbers).
The following commands should be run in a new terminal window:
```bash
curl -LO https://sheetjs.com/pres.numbers
curl -LO https://docs.sheetjs.com/pres.numbers
curl -X POST -F upload=@pres.numbers http://localhost:7262/ -J -O
```

@ -378,9 +378,9 @@ const concat_RS = (stream) => new Promise((res, rej) => {
| `gmail.com` | `imap.gmail.com` |
| `fastmail.com` | `imap.fastmail.com` |
4) Download https://sheetjs.com/pres.numbers. Using a different account, send
an email to the test account and attach the file. At the end of this step, the
test account should have an email in the inbox that has an attachment.
4) Download https://docs.sheetjs.com/pres.numbers . Using a different account,
send an email to the test account and attach the file. At the end of this step,
the test account should have an email in the inbox that has an attachment.
5) Run the script:

@ -16,7 +16,7 @@ With a familiar UI, `x-spreadsheet` is an excellent choice for a modern editor.
:::note Tested Deployments
This demo was last verified on 2023 December 04.
This demo was last verified on 2024 April 25.