diff --git a/docz/docs/07-csf/04-book.md b/docz/docs/07-csf/04-book.md
index c7d3125..095d7a0 100644
--- a/docz/docs/07-csf/04-book.md
+++ b/docz/docs/07-csf/04-book.md
@@ -85,6 +85,6 @@ discussed in more detail in ["Defined Names"](/docs/csf/features/names)
| Key | Description |
|:----------------|:-----------------------------------------------------------|
-| `CodeName` | [VBA Workbook Name](/docs/csf/features#vba-and-macros) |
+| `CodeName` | [VBA Workbook Name](/docs/csf/features/vba) |
| `date1904` | epoch: 0/false for 1900 system, 1/true for 1904 |
| `filterPrivacy` | Warn or strip personally identifying info on save |
diff --git a/docz/docs/07-csf/07-features/07-vba.md b/docz/docs/07-csf/07-features/07-vba.md
new file mode 100644
index 0000000..d7178a1
--- /dev/null
+++ b/docz/docs/07-csf/07-features/07-vba.md
@@ -0,0 +1,285 @@
+---
+sidebar_position: 7
+---
+
+import current from '/version.js';
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import CodeBlock from '@theme/CodeBlock';
+
+# VBA and Macros
+
+
+ File Format Support (click to show)
+
+Note that XLSX does not support macros. The XLSM file format is nearly
+identical to XLSX and supports macros.
+
+| Formats | Basic | Storage Representation |
+|:--------|:-----:|:-----------------------------------|
+| XLSM | ✔ | `vbaProject.bin` file in container |
+| XLSX | * | Not supported in format (use XLSM) |
+| XLSB | ✔ | `vbaProject.bin` file in container |
+| XLS | ✔ | Intercalated in CFB container |
+
+Asterisks (*) mark features that are not supported by the file formats. There is
+no way to embed VBA in the XLSX format.
+
+
+
+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
+writers automatically insert the data blobs if it is present in the workbook and
+associate with the worksheet names.
+
+:::note
+
+The `vbaraw` property stores raw bytes. [SheetJS Pro](https://sheetjs.com/pro)
+offers a special component for extracting macro text from the VBA blob, editing
+the VBA project, and exporting new VBA blobs.
+
+:::
+
+## Demos
+
+The export demos focus on [an example](pathname:///vba/SheetJSVBAFormula.xlsm)
+that includes the following user-defined functions:
+
+```vb
+Function GetFormulaA1(Cell As Range) As String
+ GetFormulaA1 = Cell.Formula
+End Function
+
+Function GetFormulaRC(Cell As Range) As String
+ GetFormulaRC = Cell.Formula2R1C1
+End Function
+```
+
+
+### Copying Macros
+
+After downloading the sample file, the demo extracts the VBA blob and creates
+a new workbook including the VBA blob. Click the button to create the file and
+open in a spreadsheet editor that supports VBA:
+
+
+
+
+```jsx live
+function SheetJSVBAFormula() { return ( ); }
+```
+
+
+
+
+0) Install the dependencies:
+
+{`\
+npm init -y
+npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
+
+
+1) Save the following script to `generate_file.js`:
+
+```js title="generate_file.js"
+const XLSX = require("xlsx");
+(async() => {
+/* Extract VBA Blob from test file */
+const url = "https://docs.sheetjs.com/vba/SheetJSVBAFormula.xlsm";
+const raw_data = await (await fetch(url)).arrayBuffer();
+const blob = XLSX.read(raw_data, {bookVBA: true}).vbaraw;
+
+/* generate worksheet and workbook */
+const worksheet = XLSX.utils.aoa_to_sheet([
+ ["Cell", "A1", "RC"],
+ [
+ {t:"n", f:"LEN(A1)"}, // A2
+ {t:"s", f:"GetFormulaA1(A2)"}, // B2
+ {t:"s", f:"GetFormulaRC(A2)"} // C2
+ ]
+]);
+const workbook = XLSX.utils.book_new();
+XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");
+
+/* add VBA blob to new workbook */
+workbook.vbaraw = blob;
+
+/* create an XLSM file and try to save to SheetJSVBANeu.xlsm */
+XLSX.writeFile(workbook, "SheetJSVBANeu.xlsm", { bookVBA: true });
+})();
+```
+
+2) Run the script:
+
+```bash
+node generate_file.js
+```
+
+This script will generate `SheetJSVBANeu.xlsm`.
+
+
+
+
+### Extracting VBA Blobs
+
+To obtain the blob, `bookVBA: 1` must be set in the `read` or `readFile` call.
+
+The following example extracts the embedded VBA blob in a workbook:
+
+
+
+
+```jsx live
+function SheetJSExtractVBA(props) {
+ const [msg, setMsg] = React.useState("Select a macro-enabled file");
+ return ( <>
+ {msg}
+ {
+ /* parse workbook with bookVBA: true */
+ const wb = XLSX.read(await e.target.files[0].arrayBuffer(), {bookVBA: true});
+
+ /* get vba blob */
+ if(!wb.vbaraw) return setMsg("No VBA found!");
+ const blob = wb.vbaraw;
+
+ /* download to vbaProject.bin */
+ setMsg("Attempting to download vbaProject.bin");
+ const url = URL.createObjectURL(new Blob([blob]));
+ const a = document.createElement("a");
+ a.download = "vbaProject.bin"; a.href = url;
+ document.body.appendChild(a); a.click();
+ document.body.removeChild(a);
+ }}/>
+ > );
+}
+```
+
+
+
+
+0) Install the dependencies:
+
+{`\
+npm init -y
+npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
+
+
+1) Save the following script to `extract_vba.js`:
+
+```js title="extract_vba.js"
+const fs = require("fs"), XLSX = require("xlsx");
+const wb = XLSX.readFile(process.argv[2], { bookVBA: true });
+if(!wb.vbaraw) throw new Error("Could not find VBA blob!");
+fs.writeFileSync("vbaProject.bin", wb.vbaraw);
+```
+
+2) Run the script:
+
+```bash
+node extract_vba.js SheetJSMacroEnabled.xlsm
+```
+
+This script will generate `vbaProject.bin`. It can be added to a new workbook.
+
+
+
+
+### Exporting Blobs
+
+To ensure the writers export the VBA blob:
+
+- The output format must support VBA (`xlsm` or `xlsb` or `xls` or `biff8`)
+- The workbook object must have a valid `vbaraw` field
+- The `write` or `writeFile` call must include the option `bookVBA: true`
+
+This example uses [`vbaProject.bin`](pathname:///vba/vbaProject.bin) from the
+[sample file](pathname:///vba/vbaProject.bin):
+
+```jsx live
+function SheetJSVBAPrepared() { return ( ); }
+```
+
+## Details
+
+### Code Names
+
+Excel will use `ThisWorkbook` (or a translation like `DieseArbeitsmappe`) as the
+default Code Name for the workbook. Each worksheet will be identified using the
+default `Sheet#` naming pattern even if the worksheet names have changed.
+
+A custom workbook code name will be stored in `wb.Workbook.WBProps.CodeName`.
+For exports, assigning the property will override the default value.
+
+Worksheet and Chartsheet code names are in the worksheet properties object at
+`wb.Workbook.Sheets[i].CodeName`. Macrosheets and Dialogsheets are ignored.
+
+The readers and writers preserve the code names, but they have to be manually
+set when adding a VBA blob to a different workbook.
+
+### Macrosheets
+
+Older versions of Excel also supported a non-VBA "macrosheet" sheet type that
+stored automation commands. These are exposed in objects with the `!type`
+property set to `"macro"`.
+
+Under the hood, Excel treats Macrosheets as normal worksheets with special
+interpretation of the function expressions.
+
+#### Detecting Macros in Workbooks
+
+The `vbaraw` field will only be set if macros are present. Macrosheets will be
+explicitly flagged. Combining the two checks yields a simple function:
+
+```js
+function wb_has_macro(wb/*:workbook*/)/*:boolean*/ {
+ if(!!wb.vbaraw) return true;
+ const sheets = wb.SheetNames.map((n) => wb.Sheets[n]);
+ return sheets.some((ws) => !!ws && ws['!type']=='macro');
+}
+```
diff --git a/docz/docs/07-csf/07-features/index.md b/docz/docs/07-csf/07-features/index.md
index 8bc91d9..d292249 100644
--- a/docz/docs/07-csf/07-features/index.md
+++ b/docz/docs/07-csf/07-features/index.md
@@ -229,71 +229,3 @@ function Visibility(props) {
-## VBA and Macros
-
-
- Format Support (click to show)
-
-**VBA Modules**: XLSM, XLSB, BIFF8 XLS
-
-
-
-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
-writers automatically insert the data blobs if it is present in the workbook and
-associate with the worksheet names.
-
-The `vbaraw` property stores raw bytes. [SheetJS Pro](https://sheetjs.com/pro)
-offers a special component for extracting macro text from the VBA blob, editing
-the VBA project, and exporting new VBA blobs.
-
-#### Round-tripping Macro Enabled Files
-
-In order to preserve macro when reading and writing files, the `bookVBA` option
-must be set to true when reading and when writing. In addition, the output file
-format must support macros. `XLSX` notably does not support macros, and `XLSM`
-should be used in its place:
-
-```js
-/* Reading data */
-var wb = XLSX.read(data, { bookVBA: true }); // read file and distill VBA blob
-var vbablob = wb.vbaraw;
-```
-
-#### Code Names
-
-Excel will use `ThisWorkbook` (or a translation like `DieseArbeitsmappe`) as the
-default Code Name for the workbook. Each worksheet will be identified using the
-default `Sheet#` naming pattern even if the worksheet names have changed.
-
-A custom workbook code name will be stored in `wb.Workbook.WBProps.CodeName`.
-For exports, assigning the property will override the default value.
-
-Worksheet and Chartsheet code names are in the worksheet properties object at
-`wb.Workbook.Sheets[i].CodeName`. Macrosheets and Dialogsheets are ignored.
-
-The readers and writers preserve the code names, but they have to be manually
-set when adding a VBA blob to a different workbook.
-
-#### Macrosheets
-
-Older versions of Excel also supported a non-VBA "macrosheet" sheet type that
-stored automation commands. These are exposed in objects with the `!type`
-property set to `"macro"`.
-
-Under the hood, Excel treats Macrosheets as normal worksheets with special
-interpretation of the function expressions.
-
-#### Detecting Macros in Workbooks
-
-The `vbaraw` field will only be set if macros are present. Macrosheets will be
-explicitly flagged. Combining the two checks yields a simple function:
-
-```js
-function wb_has_macro(wb/*:workbook*/)/*:boolean*/ {
- if(!!wb.vbaraw) return true;
- const sheets = wb.SheetNames.map((n) => wb.Sheets[n]);
- return sheets.some((ws) => !!ws && ws['!type']=='macro');
-}
-```
diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js
index cf559c7..b64ce49 100644
--- a/docz/docusaurus.config.js
+++ b/docz/docusaurus.config.js
@@ -142,7 +142,7 @@ const config = {
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme,
- additionalLanguages: [ "swift", "java", "csharp", "perl", "ruby", "cpp", "applescript", "liquid", "rust" ],
+ additionalLanguages: [ "visual-basic", "swift", "java", "csharp", "perl", "ruby", "cpp", "applescript", "liquid", "rust" ],
},
liveCodeBlock: {
playgroundPosition: 'top'
diff --git a/docz/static/vba/SheetJSVBAFormula.xlsm b/docz/static/vba/SheetJSVBAFormula.xlsm
new file mode 100644
index 0000000..148b405
Binary files /dev/null and b/docz/static/vba/SheetJSVBAFormula.xlsm differ
diff --git a/docz/static/vba/vbaProject.bin b/docz/static/vba/vbaProject.bin
new file mode 100644
index 0000000..a112350
Binary files /dev/null and b/docz/static/vba/vbaProject.bin differ