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().
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.
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.
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().
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} />;
} <script setup lang="ts">
import { onMounted, ref } from 'vue';
import { DocxViewer } from '@silurus/ooxml/docx';
const props = defineProps<{ src: string }>();
const canvas = ref<HTMLCanvasElement>();
let viewer: DocxViewer | undefined;
onMounted(() => {
viewer = new DocxViewer(canvas.value as HTMLCanvasElement, { width: 820 });
void viewer.load(props.src);
});
// DocxViewer needs no explicit teardown.
</script>
<template>
<canvas ref="canvas" />
</template> <script lang="ts">
import { onMount } from 'svelte';
import { DocxViewer } from '@silurus/ooxml/docx';
export let src: string;
let canvas: HTMLCanvasElement;
onMount(() => {
const viewer = new DocxViewer(canvas, { width: 820 });
void viewer.load(src);
});
</script>
<canvas bind:this={canvas}></canvas> import { DocxViewer } from '@silurus/ooxml/docx';
const canvas = document.getElementById('viewer') as HTMLCanvasElement;
const viewer = new DocxViewer(canvas, { width: 820 });
await viewer.load('/sample.docx'); 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
| Option | Type | Default | Description |
|---|---|---|---|
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
| Option | Type | Default | Description |
|---|---|---|---|
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. |