0.x postThis post uses the 0.x package names and APIs. For the current release see the 2.x docs.
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.
Common alternatives include:
- Server-side conversion: converts DOCX to HTML on the backend and converts the edited HTML back to DOCX. This process can omit unsupported formatting.
- Proprietary SDKs: can require per-seat licenses and add large client bundles.
- iframe embeds: limit interface customization and depend on a third-party service.
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. The following example creates 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. Parsing time depends on the document size, image data, and OOXML structure. For documents with many pages or 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
The docxtemplater plugin example shows template variable processing.
Next steps
- Browse the source code on GitHub
- Try the live demo