# docx-viewer Usage Guide

This guide explains how to run the static demo, embed the DOCX renderer in a web page, use the public API, configure rendering options, and maintain the GitHub Pages deployment.

## 1. Demo

Live demo:

https://wybaby168.github.io/docx-viewer/

The demo supports three common workflows:

- Upload a local `.docx` file with the file picker.
- Drag and drop a `.docx` file into the viewer area.
- Select a bundled fixture from the `Test Documents` menu.

After a DOCX is selected, the demo runs ZIP loading and OOXML parsing inside the Web Worker at `demo/docx-worker.js`. The main thread receives a renderable document snapshot, creates DOM nodes, and lazily requests images, fonts, charts, SmartArt, ink, and alternate chunks from the worker, so large documents keep the page responsive during parsing.

The worker uses the browser's native `DOMParser` first. If a worker environment does not expose that API, it loads `@xmldom/xmldom` from esm.sh inside the worker as an XML parsing fallback.

After DOM insertion, the demo waits for `awaitRenderedLayout()` before updating thumbnails and the `Ready` state. This ensures long documents show the completed pagination result instead of only the initial OOXML page-break groups.

The demo also sets `ignoreLastRenderedPageBreak: false`, so documents saved by Microsoft Word can use their stored `lastRenderedPageBreak` markers as the initial page map. When the worker detects those markers, the demo skips dynamic repagination for that document and uses the stored page map directly, avoiding both incomplete initial output and runaway browser-side page splitting.

The public demo keeps `debug` disabled by default so large documents do not flood the console with non-fatal OOXML compatibility notices.

The `Rendered snapshots` link opens `rendered-docx-effect.html`, a standalone page that embeds the stored `tests/render-test/**/result.html` outputs for quick visual review.

## 2. Repository Layout

Important files:

- `index.html`: the interactive demo page.
- `dist/docx-preview.js`: UMD build for plain browser scripts. It exposes `window.docx`.
- `dist/docx-preview.mjs`: ESM build for modern module imports.
- `dist/docx-preview.d.ts`: public TypeScript declarations.
- `demo/docx-preprocessor.js`: optional DOCX preprocessing reference for custom pages.
- `demo/docx-worker.js`: Web Worker used by the demo to parse DOCX files in the background.
- `demo/docx-worker-client.js`: main-thread proxy that talks to the worker, rebuilds the renderable document object, and lazy-loads resources.
- `demo/thumbnail.example.js`: optional thumbnail rendering example.
- `tests/render-test/**/document.docx`: sample DOCX files used by the demo.
- `scripts/build-pages.mjs`: copies the files needed by GitHub Pages into `_site/`.
- `scripts/check-pages.mjs`: validates the Pages artifact before CI deploys it.

## 3. Local Setup

```bash
git clone https://github.com/wybaby168/docx-viewer.git
cd docx-viewer
npm install
```

Build the static demo artifact:

```bash
npm run build:pages
npm run check:pages
```

The output is generated in `_site/`. You can serve it with any static server:

```bash
npx serve _site
```

You can also open `index.html` directly in a browser, but some browsers restrict local `fetch()` calls for bundled fixture files. A static server is more reliable.

Worker parsing should also be tested through HTTP to avoid browser-specific restrictions around `file://` workers, `fetch()`, or cross-origin script loading.

To verify a specific DOCX served from the same origin, open the demo with `?src=/path/to/document.docx`.

## 4. Plain Browser Integration

Use the UMD build when you do not have a bundler.

```html
<script src="https://unpkg.com/jszip/dist/jszip.min.js"></script>
<script src="./dist/docx-preview.js"></script>

<input id="file" type="file" accept=".docx" />
<div id="viewer"></div>

<script>
  const input = document.getElementById("file");
  const viewer = document.getElementById("viewer");

  input.addEventListener("change", async () => {
    const file = input.files[0];
    if (!file) return;

    viewer.innerHTML = "";

    await docx.renderAsync(file, viewer, null, {
      className: "docx",
      inWrapper: true,
      breakPages: true,
      renderHeaders: true,
      renderFooters: true,
      renderFootnotes: true,
      renderEndnotes: true,
      strictWordCompatibility: true
    });
  });
</script>
```

Notes:

- Load `JSZip` before `dist/docx-preview.js`.
- The UMD build exposes APIs on `window.docx`.
- The first argument can be a `Blob`, `ArrayBuffer`, `Uint8Array`, or another input type accepted by `JSZip.loadAsync`.
- For large documents, follow the demo's `demo/docx-worker-client.js` and `demo/docx-worker.js` pattern: run `parseAsync` in a Web Worker, then call `renderDocument` on the main thread to create DOM nodes.

## 5. ESM Integration

Use the ESM build in modern browsers or bundler-based applications.

```html
<div id="viewer"></div>

<script type="module">
  import { renderAsync } from "./dist/docx-preview.mjs";

  const response = await fetch("./tests/render-test/text/document.docx");
  const data = await response.blob();

  await renderAsync(data, document.getElementById("viewer"), null, {
    breakPages: true,
    strictWordCompatibility: true
  });
</script>
```

If you install this repository from GitHub in another project, the checked-in `dist/` files can be consumed by your bundler:

```bash
npm install github:wybaby168/docx-viewer
```

```ts
import { renderAsync } from "@wybaby168/docx-viewer";
```

## 6. Core API

### renderAsync

```ts
renderAsync(
  document: Blob | ArrayBuffer | Uint8Array,
  bodyContainer: HTMLElement,
  styleContainer?: HTMLElement,
  options?: Partial<Options>
): Promise<WordDocument>
```

Use `renderAsync` for most applications. It parses the DOCX and renders the resulting HTML into `bodyContainer`.

`styleContainer` is optional. If omitted or `null`, generated styles are inserted into `bodyContainer`. Use a separate style container when you want document styles outside the scrollable content area.

### parseAsync

```ts
parseAsync(
  document: Blob | ArrayBuffer | Uint8Array,
  options?: Partial<Options>
): Promise<WordDocument>
```

Parses the DOCX into an internal `WordDocument`. This is useful when you need to inspect or modify the document before rendering.

### renderDocument

```ts
renderDocument(
  wordDocument: WordDocument,
  options?: Partial<Options>
): Promise<Node[]>
```

Renders a parsed document into DOM nodes. This is lower-level than `renderAsync`.

### awaitRenderedLayout

```ts
awaitRenderedLayout(
  container: HTMLElement,
  options?: Partial<Options>
): Promise<LayoutSnapshot>
```

Waits for images, fonts, animation frames, and optional pagination work, then returns a layout snapshot.

### collectLayoutSnapshot

```ts
collectLayoutSnapshot(
  container: HTMLElement,
  options?: Partial<Options>
): LayoutSnapshot
```

Collects page count, overflow pages, field values, anchors, floating objects, and unresolved media from an already rendered document.

## 7. Rendering Options

Common options:

| Option | Default | Description |
| --- | --- | --- |
| `className` | `"docx"` | CSS class prefix used for generated document styles. |
| `inWrapper` | `true` | Wrap rendered pages in a `.docx-wrapper` container. |
| `hideWrapperOnPrint` | `false` | Hide wrapper styling when printing. |
| `ignoreWidth` | `false` | Ignore document page width. |
| `ignoreHeight` | `false` | Ignore document page height. |
| `ignoreFonts` | `false` | Disable embedded font rendering. |
| `breakPages` | `true` | Render page breaks when possible. |
| `ignoreLastRenderedPageBreak` | `true` | Ignore Word-generated `<w:lastRenderedPageBreak/>` markers. |
| `strictWordCompatibility` | `true` | Enable stricter Word-like pagination and layout behavior. |
| `paginationTolerance` | `2` | Pixel tolerance before a page is treated as overflowing. |
| `maxDynamicPaginationPasses` | `1000` | Safety cap for dynamic pagination passes. |
| `awaitLayout` | `false` | Resolve `renderAsync` after layout-related async work. |
| `experimental` | `false` | Enable experimental parsing or rendering paths. |
| `trimXmlDeclaration` | `true` | Remove XML declarations before parsing XML parts. |
| `useBase64URL` | `false` | Use base64 URLs for media instead of object URLs. |
| `renderChanges` | `false` | Render insertions/deletions when available. |
| `renderHeaders` | `true` | Render headers. |
| `renderFooters` | `true` | Render footers. |
| `renderFootnotes` | `true` | Render footnotes. |
| `renderEndnotes` | `true` | Render endnotes. |
| `renderComments` | `false` | Render comments where supported. |
| `renderAltChunks` | `true` | Render alternate HTML chunks. |
| `debug` | `false` | Log additional debugging details. |

Recommended production baseline:

```ts
const options = {
  breakPages: true,
  strictWordCompatibility: true,
  renderHeaders: true,
  renderFooters: true,
  renderFootnotes: true,
  renderEndnotes: true,
  renderComments: false,
  awaitLayout: true
};
```

## 8. Loading Remote DOCX Files

When loading a remote document, fetch it as a `Blob` or `ArrayBuffer`.

```ts
const response = await fetch("https://example.com/report.docx");

if (!response.ok) {
  throw new Error(`Failed to load DOCX: ${response.status}`);
}

const blob = await response.blob();
await renderAsync(blob, document.getElementById("viewer"));
```

The remote server must allow browser access with the correct CORS headers.

## 9. Rendering Multiple Documents

Use a separate container for each document, or clear the container before rendering a new file.

```ts
async function renderInto(container, file) {
  container.innerHTML = "";
  await docx.renderAsync(file, container, null, {
    className: "docx",
    breakPages: true
  });
}
```

If multiple documents are visible on the same page, use a different `className` per document to avoid style collisions.

## 10. GitHub Pages Deployment

This repository deploys the static demo with `.github/workflows/pages.yml`.

The workflow runs on every push to `main` and can also be started manually from the GitHub Actions tab.

Deployment steps:

1. Checkout the repository.
2. Install dependencies with `npm ci`.
3. Build `_site/` with `npm run build:pages`.
4. Validate `_site/` with `npm run check:pages`.
5. Upload `_site/` with `actions/upload-pages-artifact`.
6. Deploy the artifact with `actions/deploy-pages`.

The demo URL is:

https://wybaby168.github.io/docx-viewer/

## 11. Troubleshooting

If the page is blank:

- Check the browser console for failed script or DOCX fetch requests.
- Make sure `JSZip` is loaded before `dist/docx-preview.js` when using the UMD build.
- Serve the files through HTTP instead of opening local files directly.

If fixture loading fails:

- Confirm `tests/render-test/<name>/document.docx` exists in the deployed site.
- Run `npm run build:pages` and `npm run check:pages` locally.

If styles look mixed between documents:

- Render each document into a separate container.
- Use a unique `className` per rendered document.

If page breaks differ from Microsoft Word:

- Keep `breakPages: true`.
- Try `ignoreLastRenderedPageBreak: false` when the source DOCX contains Word-generated page break markers.
- Use `awaitLayout: true` before reading layout-dependent data.
