← All formats

DOCX

Render .docx documents to Canvas, your way.

Every demo below is the real library rendering a sample Word document (.docx) live in your browser — and the exact code that produces it. The same patterns power the Storybook stories.

Story · Demo

Single viewer with navigation

Hand DocxViewer a canvas and it manages parsing, page layout and the current page. Step through with the built-in nextPage() / prevPage().

sample-1.docx live · WASM
import { DocxViewer } from '@silurus/ooxml/docx';

// The built-in viewer tracks the current page for you.
const viewer = new DocxViewer(canvas, { width: 960, useGoogleFonts: true });
await viewer.load('/sample.docx');

nextBtn.addEventListener('click', () => viewer.nextPage());
prevBtn.addEventListener('click', () => viewer.prevPage());

Story · ScrollView

Scroll through every page

Drive the headless DocxDocument engine to render each page into its own canvas, stacked in a scroll container — the natural way to read a long document.

sample-1.docx live · WASM
import { DocxDocument } from '@silurus/ooxml/docx';

// Headless engine — render every page into a canvas you control.
const doc = await DocxDocument.load('/sample.docx');

for (let i = 0; i < doc.pageCount; i++) {
  const canvas = document.createElement('canvas');
  scroller.appendChild(canvas);
  await doc.renderPage(canvas, i, { width: 1100 });
}

Story · ThumbnailGrid

Page thumbnails

The same engine renders pages at any size. Lay them out in a grid at thumbnail width for a quick overview, with click-to-navigate.

sample-1.docx live · WASM
import { DocxDocument } from '@silurus/ooxml/docx';

// Render each page small, wire up navigation.
const doc = await DocxDocument.load('/sample.docx');

for (let i = 0; i < doc.pageCount; i++) {
  const thumb = document.createElement('canvas');
  thumb.addEventListener('click', () => open(i));
  grid.appendChild(thumb);
  await doc.renderPage(thumb, i, { width: 320 });
}

Story · MasterDetail

Thumbnail rail + large preview

Combine both: a DocxDocument for the thumbnail rail and a DocxViewer for the detail pane. Click a thumbnail to jump the preview with goToPage().

sample-1.docx live · WASM
import { DocxDocument, DocxViewer } from '@silurus/ooxml/docx';

// A large preview viewer on the right…
const viewer = new DocxViewer(detailCanvas, { width: 960, enableTextSelection: true });

// …and a thumbnail rail on the left, sharing the same file.
const [doc] = await Promise.all([
  DocxDocument.load('/sample.docx'),
  viewer.load('/sample.docx'),
]);

for (let i = 0; i < doc.pageCount; i++) {
  const thumb = document.createElement('canvas');
  thumb.addEventListener('click', () => viewer.goToPage(i));  // jump the preview
  rail.appendChild(thumb);
  await doc.renderPage(thumb, i, { width: 200 });
}

In your framework

Mount it in a canvas

The viewer is a plain TypeScript class — no framework runtime, no peer deps. Create it on mount, call load(), and let it go on unmount.

import { useEffect, useRef } from 'react';
import { DocxViewer } from '@silurus/ooxml/docx';

export function Viewer({ src }: { src: string }) {
  const ref = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    const canvas = ref.current;
    if (!canvas) return;
    const viewer = new DocxViewer(canvas, { width: 820 });
    void viewer.load(src);
    // DocxViewer renders into the canvas you own — nothing to tear down.
  }, [src]);

  return <canvas ref={ref} />;
}

API reference

Options & methods

Every public option and method, straight from the source. Types omitted for brevity are exported from the package — your editor will autocomplete the rest.

DocxViewer

Single-canvas viewer that paginates the document and tracks the current page.

new DocxViewer(canvas: HTMLCanvasElement, options?: DocxViewerOptions)

Options

OptionTypeDefaultDescription
width number Canvas CSS width in px; height is auto-computed from the page aspect ratio.
dpr number devicePixelRatio Device pixel ratio for the backing store (crispness on HiDPI).
useGoogleFonts boolean false Load metric-compatible webfonts from Google Fonts so layout matches Office without the fonts installed. Off by default for privacy.
enableTextSelection boolean false Overlay a transparent text layer for native selection & copy.
showTrackChanges boolean Render tracked insertions/deletions with author colours.
maxZipEntryBytes number 512 MiB Per-entry ZIP decompression cap (zip-bomb guard). Lower it for untrusted input.
math MathRenderer undefined Opt-in OMML equation engine (MathJax + STIX Two Math, ~3 MB). Import it from the separate @silurus/ooxml/math entry — `import { math } from "@silurus/ooxml/math"` — and pass it to render equations. Omit it and equations are skipped — the engine tree-shakes away entirely.
onPageChange (index: number, total: number) => void Called after a page finishes rendering.
onError (err: Error) => void Called on parse or render errors.

Methods

load(source: string | ArrayBuffer): Promise<void> Load from a URL or ArrayBuffer and render the first page.
goToPage(index: number): Promise<void> Render a specific page (0-indexed, clamped).
nextPage(): Promise<void> Advance one page.
prevPage(): Promise<void> Go back one page.
get pageCount(): number Total pages (0 until loaded).
get currentPage(): number Current page index.
get canvasElement(): HTMLCanvasElement The underlying canvas.
destroy(): void Tear down the worker and release resources.

DocxDocument

Headless engine — render any page into any canvas you supply.

await DocxDocument.load(source, options?)

Options

OptionTypeDefaultDescription
useGoogleFonts boolean false Load metric-compatible webfonts from Google Fonts so layout matches Office without the fonts installed. Off by default for privacy.
maxZipEntryBytes number 512 MiB Per-entry ZIP decompression cap (zip-bomb guard). Lower it for untrusted input.
math MathRenderer undefined Opt-in OMML equation engine (MathJax + STIX Two Math, ~3 MB). Import it from the separate @silurus/ooxml/math entry — `import { math } from "@silurus/ooxml/math"` — and pass it to render equations. Omit it and equations are skipped — the engine tree-shakes away entirely.

Methods

static load(source, options?): Promise<DocxDocument> Parse a document from a URL or ArrayBuffer.
get pageCount(): number Total pages.
renderPage(canvas, index, opts?: { width?, dpr?, showTrackChanges? }): Promise<void> Render one page into the given canvas.