Recipes
Working code for common tasks. Every snippet is a real file under site/src/lib/examples/ that is type-checked against the library on every build, so an API rename breaks this page before it ships. For a specific function, see the API reference.
Mail-merge across every part of the package
replaceTextEverywhere walks the body, headers, footers, footnotes, endnotes, and comments, so a placeholder in a header is filled the same way one in the body is.
// Mail-merge across every text-bearing part of the package — body,
// headers, footers, footnotes, endnotes, comments. replaceTextEverywhere
// follows the same regex/callback contract as replaceText but walks the
// whole document, so a {{name}} hidden in a header is filled the same
// way one in the body is.
import { openDocx, replaceTextEverywhere, toUint8Array } from "@office-kit/docx";
declare const templateBytes: Uint8Array;
declare const values: Record<string, string>;
const doc = openDocx(templateBytes);
// Regex captures land in `m.captures`; everything else (`m.match`,
// `m.index`) mirrors RegExp.exec semantics. Run-spanning matches are
// joined before the regex sees them, so `{{name}}` split across
// multiple runs still substitutes cleanly.
const replaced: number = replaceTextEverywhere(
doc,
/\{\{(\w+)\}\}/g,
(m) => values[m.captures[0] ?? ""] ?? "",
);
console.log(`replaced ${replaced} placeholders`);
const filled: Uint8Array = toUint8Array(doc);
void filled;
pnpm sample writes samples/21-mailmerge-cross-part-template.docx and -filled.docx.
Start from a designed base
Open a hand-designed .docx, lift its style table into your authoring graph with mergeStylesFromTemplate, then keep appending. Custom styles applied by name via setParagraphStyle.
// PowerPoint-style "designed base": open a hand-designed .docx, lift
// only its style table into your authoring graph, then keep appending
// body content. The visual identity (fonts, colours, custom paragraph
// styles) carries over without any placeholder-substitution dance.
import {
appendHeading,
appendParagraph,
createDocx,
findStyleIdByName,
mergeStylesFromTemplate,
setParagraphStyle,
toUint8Array,
} from "@office-kit/docx";
declare const templateBytes: Uint8Array;
const doc = createDocx({ paragraphs: [] });
// Merge styles from the hand-designed template into the empty doc.
// `overwrite: false` (default) means built-in heading styles in the
// authoring graph win if both define them; pass `overwrite: true` to
// take the template's flavour.
const merged: number = mergeStylesFromTemplate(doc, templateBytes);
console.log(`merged ${merged} styles from template`);
appendHeading(doc, "Quarterly review", 1);
// Apply a custom paragraph style by *name* (as it appears in Word's UI)
// rather than the raw `w:styleId`. Returns the underlying styleId so
// downstream code can re-use it.
const calloutId: string | undefined = findStyleIdByName(doc, "Callout");
const callout = appendParagraph(doc, "Heads-up: this is the executive summary.");
if (calloutId) setParagraphStyle(callout, calloutId);
const bytes: Uint8Array = toUint8Array(doc);
void bytes;
pnpm sample writes samples/30-styled-base-template.docx and -filled.docx.
Accept or reject tracked changes in bulk
acceptAllRevisions inlines suggested inserts and bakes in deletions. rejectAllRevisions does the inverse — useful for producing both 'final' and 'original' branches from one reviewed doc.
// Resolve tracked changes (Word's "Accept / Reject all changes") in
// bulk. The library walks every w:ins / w:del marker in the document
// body and either bakes it in or removes it.
//
// `acceptAllRevisions` inlines the inserted ranges and deletes the
// deleted ones. `rejectAllRevisions` does the reverse: keeps deletions
// (= drops the suggested insertions) and restores deleted ranges.
import { acceptAllRevisions, openDocx, rejectAllRevisions, toUint8Array } from "@office-kit/docx";
declare const reviewedBytes: Uint8Array;
// Final draft: accept everything the editor suggested.
const accepted = openDocx(reviewedBytes);
const acceptedCount: number = acceptAllRevisions(accepted);
console.log(`accepted ${acceptedCount} revisions`);
const finalBytes: Uint8Array = toUint8Array(accepted);
// Sometimes you want the opposite — revert all proposed changes.
const reverted = openDocx(reviewedBytes);
const rejectedCount: number = rejectAllRevisions(reverted);
console.log(`rejected ${rejectedCount} revisions`);
const originalBytes: Uint8Array = toUint8Array(reverted);
void finalBytes;
void originalBytes;
pnpm sample writes samples/09-tracked-changes.docx.
Render in the browser with @office-kit/docx-preview
previewToDOM mounts a read-only render of any Docx into a DOM container. Returns an idempotent dispose handle.
// Render any Docx — built from scratch or opened from bytes — into a
// DOM container using @office-kit/docx-preview. The wrap is intentional: we
// share the renderer with docx-preview upstream but pin the contract
// behind a stable function-API surface.
import { openDocx } from "@office-kit/docx";
import { previewToDOM } from "@office-kit/docx-preview";
declare const bytes: Uint8Array;
declare const container: HTMLElement;
const doc = openDocx(bytes);
const handle = await previewToDOM(doc, container, {
classPrefix: "wk-",
inWrapper: true,
breakPages: true,
renderFonts: true,
});
// when you're done, detach + release internal references:
handle.dispose();
The playground on this site runs this code.
To build a document end to end, walk through Getting started, then open the playground to see the rendered output.