+
+
+
+
+`XMLHttpRequest` and `fetch` browser APIs enable binary data transfer between
+web browser clients and web servers. Since this library works in web browsers,
+server conversion work can be offloaded to the client! This demo shows a few
+common scenarios involving browser APIs and popular wrapper libraries.
+
+:::caution Third-Party Hosts and Binary Data
+
+Some services like AWS will corrupt raw binary uploads / downloads by encoding
+requests and responses in UTF-8. Typically, these services have options for
+disabling this behavior.
+
+For AWS, in the "Binary Media Types" section of the API Gateway console, the
+following types should be added to ensure smooth uploads and downloads:
+
+- `"multipart/form-data"` (for Lambda functions to receive files from clients)
+- `"application/vnd.ms-excel"` (for Lambda functions to send files to clients)
+
+:::
+
+## Downloading Binary Data
+
+Most interesting spreadsheet files are binary data that contain byte sequences
+that represent invalid UTF-8 characters.
+
+The APIs generally have a way to control the interpretation of the downloaded
+data. The `arraybuffer` response type usually forces the data to be presented
+as a pure `ArrayBuffer` which can be parsed directly with `XLSX.read`.
+
+For example, with `fetch`:
+
+```js
+const res = await fetch("https://sheetjs.com/pres.numbers");
+const ab = res.arrayBuffer(); // recover data as ArrayBuffer
+
+const wb = XLSX.read(ab);
+```
+
+## Uploading Binary Data
+
+`FormData` objects can hold `File` blobs generated from `XLSX.write`:
+
+```js
+/* generate XLSX file bytes */
+var data = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'});
+
+/* build FormData with the generated file */
+var fdata = new FormData();
+fdata.append('data', new File([data], 'sheetjs.xlsx'));
+// field name ^^^^ file name ^^^^^^^^^^^^
+```
+
+The `FormData` object can be passed along to the POST request. For example:
+
+```js
+var req = new XMLHttpRequest();
+req.open("POST", "/upload", true);
+req.send(fdata);
+```
+
+## Browser Demos
+
+The included demos focus on an editable table. There are two separate flows:
+
+- When the page is accessed, the browser will attempt to download
+ and read the workbook. The old table will be replaced with an editable table
+ whose contents match the first worksheet. The table is generated using the
+ `sheet_to_html` utility with `editable:true` option
+
+- When the upload button is clicked, the browser will generate a new worksheet
+ using `table_to_book` and build up a new workbook. It will then attempt to
+ generate a file, upload it to and show the response.
+
+### XMLHttpRequest
+
+For downloading data, the `arraybuffer` response type generates an `ArrayBuffer`
+that can be viewed as an `Uint8Array` and fed to `XLSX.read` using `array` type:
+
+```js
+/* set up an async GET request */
+var req = new XMLHttpRequest();
+req.open("GET", url, true);
+req.responseType = "arraybuffer";
+
+req.onload = function(e) {
+ /* parse the data when it is received */
+ var data = new Uint8Array(req.response);
+ var workbook = XLSX.read(data, {type:"array"});
+ /* DO SOMETHING WITH workbook HERE */
+};
+req.send();
+```
+
+Live Download demo (click to show)
+
+This demo uses `XMLHttpRequest` to download
+and show the data in an HTML table.
+
+```jsx live
+function SheetJSXHRDL() {
+ const [html, setHTML] = React.useState("");
+
+ /* Fetch and update HTML */
+ React.useEffect(async() => {
+ /* Fetch file */
+ const req = new XMLHttpRequest();
+ req.open("GET", "https://sheetjs.com/pres.numbers", true);
+ req.responseType = "arraybuffer";
+ req.onload = e => {
+ /* Parse file */
+ const wb = XLSX.read(new Uint8Array(req.response));
+ const ws = wb.Sheets[wb.SheetNames[0]];
+
+ /* Generate HTML */
+ setHTML(XLSX.utils.sheet_to_html(ws));
+ };
+ req.send();
+ }, []);
+
+ return ();
+}
+```
+
+
+
+For uploading data, this demo populates a `FormData` object with an ArrayBuffer
+generated with the `array` output type:
+
+```js
+/* generate XLSX as array buffer */
+var data = XLSX.write(workbook, {bookType: 'xlsx', type: 'array'});
+
+/* build FormData with the generated file */
+var fd = new FormData();
+fd.append('data', new File([data], 'sheetjs.xlsx'));
+
+/* send data */
+var req = new XMLHttpRequest();
+req.open("POST", url, true);
+req.send(fd);
+```
+
+Live Upload demo (click to show)
+
+This demo uses `XMLHttpRequest` to upload data to . It
+will parse the workbook and return an HTML table.
+
+```jsx live
+function SheetJSXHRUL() {
+ const [html, setHTML] = React.useState("");
+ const [sz, setSz] = React.useState(0);
+ const csv = "a,b,c\n1,2,3";
+ /* Fetch and update HTML */
+ const xport = React.useCallback(async() => {
+ /* Make Workbook from CSV */
+ const wb = XLSX.read(csv, { type: "string" });
+
+ /* Make FormData */
+ const data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
+ setSz(data.length || data.byteLength);
+ const fdata = new FormData();
+ fdata.append('file', new File([data], 'sheetjs.xlsx'));
+
+ /* Upload */
+ const url = "https://s2c.sheetjs.com";
+ const req = new XMLHttpRequest();
+ req.open("POST", url, true);
+ req.onload = (e) => setHTML(req.responseText);
+ req.send(fdata);
+ });
+
+ return (
);
+}
+```
+
+
diff --git a/docz/docs/04-getting-started/03-demos/06-clipboard.md b/docz/docs/04-getting-started/03-demos/17-clipboard.md
similarity index 96%
rename from docz/docs/04-getting-started/03-demos/06-clipboard.md
rename to docz/docs/04-getting-started/03-demos/17-clipboard.md
index 2c9bedde..2bfbe841 100644
--- a/docz/docs/04-getting-started/03-demos/06-clipboard.md
+++ b/docz/docs/04-getting-started/03-demos/17-clipboard.md
@@ -1,5 +1,5 @@
---
-sidebar_position: 6
+sidebar_position: 17
---
# Clipboard Data
diff --git a/docz/docs/04-getting-started/03-demos/index.md b/docz/docs/04-getting-started/03-demos/index.md
index 2f4cff60..222371cf 100644
--- a/docz/docs/04-getting-started/03-demos/index.md
+++ b/docz/docs/04-getting-started/03-demos/index.md
@@ -9,7 +9,7 @@ The demo projects include small runnable examples and short explainers.
### JavaScript APIs
-- [`XMLHttpRequest and fetch`](https://github.com/SheetJS/SheetJS/tree/master/demos/xhr/)
+- [`XMLHttpRequest and fetch`](./network)
- [`Clipboard Data`](./clipboard)
- [`Typed Arrays for Machine Learning`](./ml)
- [`LocalStorage and SessionStorage`](./database#localstorage-and-sessionstorage)
diff --git a/docz/docs/06-solutions/01-input.md b/docz/docs/06-solutions/01-input.md
index a55b581e..48804ddd 100644
--- a/docz/docs/06-solutions/01-input.md
+++ b/docz/docs/06-solutions/01-input.md
@@ -463,7 +463,7 @@ req.onload = function(e) {
req.send();
```
-The [`xhr` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/xhr/) includes a longer discussion and more examples.
+The [`xhr` demo](../getting-started/demos/network) includes a longer discussion and more examples.
shows fallback approaches for IE6+.
diff --git a/docz/docs/06-solutions/05-output.md b/docz/docs/06-solutions/05-output.md
index f8fecc35..646047b8 100644
--- a/docz/docs/06-solutions/05-output.md
+++ b/docz/docs/06-solutions/05-output.md
@@ -489,7 +489,7 @@ is to adjust the server process or Lambda function to accept Base64 strings.
:::
-A complete example using XHR is [included in the XHR demo](https://github.com/SheetJS/SheetJS/tree/master/demos/xhr/), along
+A complete example using XHR is [included in the XHR demo](../getting-started/demos/network), along
with examples for fetch and wrapper libraries. This example assumes the server
can handle Base64-encoded files (see the demo for a basic nodejs server):