diff --git a/docz/docs/03-demos/04-grid/10-tabulator.md b/docz/docs/03-demos/04-grid/10-tabulator.md
new file mode 100644
index 0000000..d37bbab
--- /dev/null
+++ b/docz/docs/03-demos/04-grid/10-tabulator.md
@@ -0,0 +1,167 @@
+---
+title: Tabulator
+pagination_prev: demos/frontend/index
+pagination_next: demos/net/index
+---
+
+import current from '/version.js';
+import CodeBlock from '@theme/CodeBlock';
+
+[Tabulator](https://tabulator.info/) is a powerful data table library designed
+for ease of use.
+
+[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
+data from spreadsheets.
+
+Tabulator offers deep integration with SheetJS for importing and exporting data.
+This demo covers additional detail including document customization.
+
+[Click here for a live standalone integration demo.](pathname:///tabulator/)
+
+:::note Tested Deployments
+
+This demo was tested in the following deployments:
+
+| Browser      | Version | Date       |
+|:-------------|:--------|:-----------|
+| Chromium 125 | `6.2.1` | 2024-06-13 |
+
+:::
+
+## Integration Details
+
+The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
+are appropriate for sites that use the Tabulator CDN scripts.
+
+[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
+installation instructions for projects using a framework.
+
+:::info pass
+
+**The Tabulator script must be loaded after the SheetJS scripts!**
+
+```html
+<!-- Load SheetJS Scripts -->
+<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
+<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
+<!-- Tabulator must be loaded after SheetJS scripts -->
+<script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.2.1/dist/js/tabulator.min.js"></script>
+```
+
+:::
+
+### Previewing Data
+
+Tabulator offers a special `setData` method for assigning data after the table
+is created. Coupled with the `autoColumns` option, Tabulator will automatically
+refresh the table.
+
+:::info pass
+
+The library scans the first row object to determine the header labels. If a
+column is missing a value in the first object, it will not be loaded!
+
+:::
+
+#### Fetching Files
+
+When files are stored remotely, the recommended approach is to fetch the files,
+parse with the SheetJS `read` method, generate arrays of objects from the target
+sheet using `sheet_to_json`, and load data with the Tabulator `setData` method.
+The following snippet fetches a sample file and loads the first sheet:
+
+```html title="Fetching a spreadsheet and Displaying the first worksheet"
+<!-- Tabulator DIV -->
+<div id="htmlout"></div>
+
+<script>
+/* Initialize Tabulator with the `autoColumns: true` setting */
+var tbl = new Tabulator('#htmlout', { autoColumns: true });
+
+/* fetch and display https://docs.sheetjs.com/pres.numbers */
+(function() { try {
+  fetch("https://docs.sheetjs.com/pres.numbers")
+    .then(function(res) { return res.arrayBuffer(); })
+    .then(function(ab) {
+      /* parse ArrayBuffer */
+      var wb = XLSX.read(ab);
+      /* get first worksheet from SheetJS workbook object */
+      var ws = wb.Sheets[wb.SheetNames[0]];
+      /* generate array of row objects */
+      var data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
+      /* update Tabulator */
+      tbl.setData(data);
+    });
+} catch(e) {} })();
+</script>
+```
+
+#### Local Files
+
+Tabulator provides a special `import` method to show a dialog and load data.
+Since the importer requires the raw binary data, the method must be called with
+the third argument set to `"buffer"`:
+
+```html title="Parsing a local spreadsheet and Displaying the first worksheet"
+<button id="imp"><b>Click here to import from XLSX file</b></button>
+<!-- Tabulator DIV -->
+<div id="htmlout"></div>
+
+<script>
+/* Initialize Tabulator with the `autoColumns: true` setting */
+var tbl = new Tabulator('#htmlout', { autoColumns: true });
+
+/* use Tabulator SheetJS integration to import data */
+document.getElementById("imp").addEventListener("click", function() {
+  tbl.import("xlsx", ".xlsx", "buffer");
+})
+</script>
+```
+
+### Saving Data
+
+Tabulator provides a special `download` method to initiate the export:
+
+```html title="Exporting data from Tabulator to XLSX"
+<input type="submit" value="Export to XLSX!" id="xport" onclick="export_xlsx();">
+<!-- Tabulator DIV -->
+<div id="htmlout"></div>
+
+<script>
+/* Initialize Tabulator with the `autoColumns: true` setting */
+var tbl = new Tabulator('#htmlout', { autoColumns: true });
+
+/* use Tabulator SheetJS integration to import data */
+function export_xlsx() {
+  /* use Tabulator SheetJS integration */
+  tbl.download("xlsx", "SheetJSTabulator.xlsx");
+}
+</script>
+```
+
+[The official documentation](https://tabulator.info/docs/6.2/download#xlsx)
+covers supported options.
+
+#### Post-processing
+
+The `documentProcessing` event handler is called after Tabulator generates a
+SheetJS workbook object. This allows for adjustments before creating the final
+workbook file. The following example adds a second sheet that includes the date:
+
+```js title="Exporting data and metadata"
+tbl.download("xlsx", "SheetJSTabulator.xlsx", {
+  documentProcessing: function(wb) {
+
+    /* create a new worksheet */
+    var ws = XLSX.utils.aoa_to_sheet([
+      ["SheetJS + Tabulator Demo"],
+      ["Export Date:", new Date()]
+    ]);
+
+    /* add to workbook */
+    XLSX.utils.book_append_sheet(wb, ws, "Metadata");
+
+    return wb;
+  }
+});
+```
diff --git a/docz/docs/03-demos/04-grid/12-vtl.md b/docz/docs/03-demos/04-grid/12-vtl.md
index 6ff4b1b..2936a05 100644
--- a/docz/docs/03-demos/04-grid/12-vtl.md
+++ b/docz/docs/03-demos/04-grid/12-vtl.md
@@ -7,23 +7,45 @@ pagination_next: demos/net/index
 import current from '/version.js';
 import CodeBlock from '@theme/CodeBlock';
 
-:::note Tested Deployments
+[Vue 3 Table Lite](https://vue3-lite-table.vercel.app/) is a data table library
+designed for the VueJS web framework.
 
-This demo was tested against `vue3-table-lite 1.3.9`, VueJS `3.3.10` and ViteJS
-`5.0.5` on 2023 December 04.
+[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
+data from spreadsheets.
 
-:::
+This demo uses Vue 3 Table Lite and SheetJS to pull data from a spreadsheet and
+display the content in a data table. We'll explore how to import data from files
+into the data grid and how to export modified data from the grid to workbooks.
 
-
-The demo creates a site that looks like the screenshot below:
+The ["Demo"](#demo) section includes a complete example that displays data from
+user-supplied sheets and exports data to XLSX workbooks:
 
 ![vue3-table-lite screenshot](pathname:///vtl/vtl1.png)
 
+:::note Tested Deployments
+
+This demo was tested in the following deployments:
+
+| Browser      | Version | Date       |
+|:-------------|:--------|:-----------|
+| Chromium 125 | `1.4.0` | 2024-06-13 |
+
+:::
+
 ## Integration Details
 
+[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
+installation in ViteJS projects using Vue 3 Table Lite.
+
+Using the `npm` tool, this command installs SheetJS and Vue 3 Table Lite:
+
+<CodeBlock language="bash">{`\
+npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz vue3-table-lite@1.4.0`}
+</CodeBlock>
+
 #### Rows and Columns Bindings
 
-`vue3-table-lite` presents two attribute bindings: an array of column metadata
+Vue 3 Table Lite presents two attribute bindings: an array of column metadata
 (`columns`) and an array of objects representing the displayed data (`rows`).
 Typically both are `ref` objects:
 
@@ -114,7 +136,7 @@ cd sheetjs-vtl
 2) Install dependencies:
 
 <CodeBlock language="bash">{`\
-npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz vue3-table-lite@1.3.9`}
+npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz vue3-table-lite@1.4.0`}
 </CodeBlock>
 
 3) Download [`src/App.vue`](pathname:///vtl/App.vue) and replace the contents:
diff --git a/docz/docs/03-demos/04-grid/index.md b/docz/docs/03-demos/04-grid/index.md
index 08ee8ed..c5fab55 100644
--- a/docz/docs/03-demos/04-grid/index.md
+++ b/docz/docs/03-demos/04-grid/index.md
@@ -30,8 +30,7 @@ The `sheet_to_json` utility function generates arrays of objects, which is
 suitable for a number of libraries.  When more advanced shapes are needed,
 it is easier to process an array of arrays.
 
-
-### x-spreadsheet
+#### x-spreadsheet
 
 With a familiar UI, `x-spreadsheet` is an excellent choice for a modern editor.
 
@@ -39,7 +38,7 @@ With a familiar UI, `x-spreadsheet` is an excellent choice for a modern editor.
 
 **[The exposition has been moved to a separate page.](/docs/demos/grid/xs)**
 
-### Canvas Datagrid
+#### Canvas Datagrid
 
 After extensive testing, `canvas-datagrid` stood out as a high-performance grid
 with a straightforward API.
@@ -48,13 +47,14 @@ with a straightforward API.
 
 **[The exposition has been moved to a separate page.](/docs/demos/grid/cdg)**
 
-### Tabulator
+#### Tabulator
 
 [Tabulator](https://tabulator.info/docs/5.4/download#xlsx) includes deep support
 through a special Export button.  It handles the SheetJS operations internally.
 
+**[The exposition has been moved to a separate page.](/docs/demos/grid/tabulator)**
 
-### Angular UI Grid
+#### Angular UI Grid
 
 :::danger pass
 
@@ -134,7 +134,7 @@ TABLE elements and when writing to XLSX and other spreadsheet formats.
 
 :::
 
-### Fixed Tables
+#### Fixed Tables
 
 When the page has a raw HTML table, the easiest solution is to attach an `id`:
 
@@ -171,10 +171,10 @@ XLSX.writeFile(wb, "HTMLFlicker.xlsx");
 document.body.removeChild(tbl);
 ```
 
-### React
+#### React
 
 **[The exposition has been moved to a separate page.](/docs/demos/frontend/react#html)**
 
-### Material UI Table
+#### Material UI Table
 
 **[The exposition has been moved to a separate page.](/docs/demos/grid/mui#material-ui-table)**
diff --git a/docz/docs/03-demos/32-extensions/01-extendscript.md b/docz/docs/03-demos/32-extensions/01-extendscript.md
index b80c4b8..5b6f40d 100644
--- a/docz/docs/03-demos/32-extensions/01-extendscript.md
+++ b/docz/docs/03-demos/32-extensions/01-extendscript.md
@@ -33,7 +33,7 @@ versions of Photoshop and InDesign:
   Suite. App automation uses ExtendScript, but integration logic uses modern JS.
 
 - ["Unified Extensibility Platform" (UXP)](#uxp): This platform supports modern
-  JavaScript but has limited support (Photoshop 2021+ and InDesign 2022+)
+  JavaScript but is only supported in recent releases of Photoshop and InDesign.
 
 :::note Tested Deployments
 
@@ -241,7 +241,7 @@ manifest must include the following flags to enable `cep.fs`:
 With newer versions of Creative Cloud apps, a special player debug mode must be
 enabled to use unsigned extensions. The command depends on the CEP version.
 
-InDesign and PhotoShop 2024 use CEP 11. In the examples, the `11` should be
+InDesign and Photoshop 2024 use CEP 11. In the examples, the `11` should be
 replaced with the appropriate CEP version number.
 
 On Windows, within the registry key `HKEY_CURRENT_USER\SOFTWARE\Adobe\CSXS.11`,
diff --git a/docz/static/tabulator/index.html b/docz/static/tabulator/index.html
new file mode 100644
index 0000000..432f685
--- /dev/null
+++ b/docz/static/tabulator/index.html
@@ -0,0 +1,112 @@
+<!DOCTYPE html>
+<!-- sheetjs (C) SheetJS https://sheetjs.com -->
+<!-- vim: set ts=2: -->
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<meta name="robots" content="noindex"/>
+<title>SheetJS + Tabulator Live Demo</title>
+<style>
+#drop{
+  border:2px dashed #bbb;
+  -moz-border-radius:5px;
+  -webkit-border-radius:5px;
+  border-radius:5px;
+  padding:25px;
+  text-align:center;
+  font:20pt bold,"Vollkorn";color:#bbb
+}
+a { text-decoration: none }
+</style>
+<!-- tabulator stylesheet -->
+<link href="https://unpkg.com/tabulator-tables@6.2.1/dist/css/tabulator.min.css" rel="stylesheet">
+</head>
+<body>
+<pre>
+<b><a href="https://sheetjs.com">SheetJS + Tabulator Demo</a></b>
+<button id="imp"><b>Click here to import</b></button>
+</pre>
+<p><input type="submit" value="Export to XLSX!" id="xport" onclick="export_xlsx();"></p>
+<div id="htmlout"></div>
+<br />
+<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
+<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
+<!-- Tabulator must be loaded after SheetJS scripts -->
+<script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.2.1/dist/js/tabulator.min.js"></script>
+<script>
+/*jshint browser:true */
+/* eslint-env browser */
+/* eslint no-use-before-define:0 */
+/*global XLSX */
+
+var tbl = new Tabulator('#htmlout', { autoColumns: true });
+var HTMLOUT = document.getElementById('htmlout')
+HTMLOUT.style.height = (window.innerHeight - 400) + "px";
+HTMLOUT.style.width = (window.innerWidth - 50) + "px";
+
+var process_wb = (function() {
+  var XPORT = document.getElementById('xport');
+
+  return function process_wb(wb) {
+    var data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
+    tbl.setData(data);
+    XPORT.disabled = false;
+
+    if(typeof console !== 'undefined') console.log("output", new Date());
+  };
+})();
+
+var do_file = (function() {
+  return function do_file(files) {
+    var f = files[0];
+    var reader = new FileReader();
+    reader.onload = function(e) {
+      if(typeof console !== 'undefined') console.log("onload", new Date());
+      var data = e.target.result;
+      process_wb(XLSX.read(data));
+    };
+    reader.readAsArrayBuffer(f);
+  };
+})();
+
+(function() {
+  try {
+    fetch("https://docs.sheetjs.com/pres.numbers")
+      .then(function(res) { return res.arrayBuffer(); })
+      .then(function(ab) { process_wb(XLSX.read(ab)); });
+  } catch(e) {}
+})();
+
+document.getElementById("imp").addEventListener("click", function() {
+  /* use Tabulator SheetJS integration */
+  tbl.import("xlsx", ".xlsx", "buffer");
+});
+
+function export_xlsx() {
+  /* use Tabulator SheetJS integration */
+  tbl.download("xlsx", "SheetJSTabulator.xlsx", {
+    documentProcessing: function(wb) {
+      var ws = XLSX.utils.aoa_to_sheet([
+        ["SheetJS + Tabulator Demo"],
+        ["Export Date:", new Date()]
+      ]);
+      XLSX.utils.book_append_sheet(wb, ws, "Metadata");
+      return wb;
+    }
+  });
+}
+</script>
+<script type="text/javascript">
+/* eslint no-use-before-define:0 */
+  var _gaq = _gaq || [];
+  _gaq.push(['_setAccount', 'UA-36810333-1']);
+  _gaq.push(['_trackPageview']);
+
+  (function() {
+    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
+  })();
+</script>
+</body>
+</html>
diff --git a/docz/static/vtl/vtl1.png b/docz/static/vtl/vtl1.png
index b53ae4d..60913ea 100644
Binary files a/docz/static/vtl/vtl1.png and b/docz/static/vtl/vtl1.png differ