0.x postThis post uses the 0.x package names and APIs. For the current release see the 1.x docs and the migration guide.
Use case
If your React app handles contracts, invoices, reports, or letters, users may need to edit .docx files without downloading them, opening Word, and re-uploading the result.
Until recently, the only options were:
- Server-side conversion: convert to HTML on the backend, lose formatting, convert back. Fragile and expensive to host.
- Proprietary SDKs: lock-in, per-seat licensing, heavy bundles.
- iframe embeds: limited control, no customization, dependent on third-party availability.
docx-js-editor parses OOXML on the client, renders it with ProseMirror, and exports back to .docx in the browser.
Prerequisites
You need a React project. Vite, Next.js, Remix, and Astro all work as long as the editor component renders on the client.
node --version # v18 or laterStep 1: Install the package
npm install @eigenpal/docx-js-editorOr with your preferred package manager:
# yarn
yarn add @eigenpal/docx-js-editor
# pnpm
pnpm add @eigenpal/docx-js-editor
# bun
bun add @eigenpal/docx-js-editorStep 2: Create the editor component
The editor needs a .docx file as an ArrayBuffer. Here's a minimal component:
import { useState, useEffect } from "react";
import { DocxEditor } from "@eigenpal/docx-js-editor";
export function MyDocxEditor() {
const [buffer, setBuffer] = useState<ArrayBuffer | null>(null);
useEffect(() => {
fetch("/sample.docx")
.then((res) => res.arrayBuffer())
.then(setBuffer);
}, []);
if (!buffer) return <p>Loading document...</p>;
return (
<div style={{ height: "80vh" }}>
<DocxEditor
documentBuffer={buffer}
onSave={(blob) => {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "edited.docx";
a.click();
URL.revokeObjectURL(url);
}}
/>
</div>
);
}This mounts a DOCX editor and downloads the saved document from onSave.
Step 3: Handle file uploads
Let users upload their own documents:
function handleUpload(event: React.ChangeEvent<HTMLInputElement>) {
const file = event.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
setBuffer(reader.result as ArrayBuffer);
};
reader.readAsArrayBuffer(file);
}Add an upload button above the editor:
<input type="file" accept=".docx" onChange={handleUpload} />Step 4: Next.js
Mark your component as 'use client':
"use client";
import { DocxEditor } from "@eigenpal/docx-js-editor";
import "@eigenpal/docx-js-editor/styles.css";
export function MyDocxEditor({ buffer }: { buffer: ArrayBuffer }) {
return <DocxEditor documentBuffer={buffer} showToolbar />;
}What the editor supports
Supported areas include:
- Rich text formatting: bold, italic, underline, strikethrough, font size, font family, colors
- Tables: cell merging, borders, column widths
- Images: inline and floating image positioning
- Page layout: headers, footers, page breaks, margins
- Tracked changes: insertions, deletions, and formatting revisions with accept/reject
- Comments: threaded document comments anchored to text ranges
- Zoom control: zoom slider and page navigation
- Document templates: variable placeholders via docxtemplater integration
Performance considerations
The editor parses OOXML directly in the browser. For typical business documents (1-20 pages), parsing takes under a second. For very large documents (100+ pages with many images), consider:
- Showing a loading spinner during parse
- Lazy-loading the editor component
- Compressing images before embedding
Framework examples
Working examples with source code are available for each framework:
- Vite example: responsive zoom, mobile detection, and document name editing
- Next.js example. App Router setup
- Remix example: lazy loading with Suspense fallback
- Astro example: island architecture with client-side rendering
There's also a docxtemplater plugin example showing template variable processing.
Next steps
- Browse the source code on GitHub
- Try the live demo
- Read about building a document template system