To edit DOCX in a Next.js app, install @eigenpal/docx-editor-react, render <DocxEditor> inside a "use client" component, and pass an ArrayBuffer. The editor parses Word OOXML in the browser. This guide covers install, the client component, file input handling, saving to an API route, and common SSR errors.
Live demo
This editor runs in the Next.js app you're reading right now. The demo does not upload the document; it stays in the browser.
Install
npm install @eigenpal/docx-editor-reactEditor component
"use client";
import { useState, useEffect, useRef, useCallback } from "react";
import { DocxEditor } from "@eigenpal/docx-editor-react";
import type { DocxEditorRef } from "@eigenpal/docx-editor-react";
import "@eigenpal/docx-editor-react/styles.css";
export function MyDocxEditor() {
const editorRef = useRef<DocxEditorRef>(null);
const [buffer, setBuffer] = useState<ArrayBuffer | null>(null);
useEffect(() => {
fetch("/sample.docx")
.then((res) => res.arrayBuffer())
.then(setBuffer);
}, []);
const handleSave = useCallback(async () => {
const saved = await editorRef.current?.save();
if (!saved) return;
const blob = new Blob([saved], {
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
const url = URL.createObjectURL(blob);
Object.assign(document.createElement("a"), {
href: url,
download: "edited.docx",
}).click();
URL.revokeObjectURL(url);
}, []);
if (!buffer) return <div>Loading...</div>;
return (
<div style={{ height: "80vh" }}>
<DocxEditor
ref={editorRef}
documentBuffer={buffer}
showToolbar
showRuler
showZoomControl
/>
<button onClick={handleSave}>Download .docx</button>
</div>
);
}"use client" is required. The component uses refs, hooks, and browser globals.
Load it in a page
import { MyDocxEditor } from "@/components/DocxEditor";
export default function EditorPage() {
return <MyDocxEditor />;
}File uploads
function handleUpload(e: React.ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => setBuffer(reader.result as ArrayBuffer);
reader.readAsArrayBuffer(file);
}Swap the buffer and the editor re-renders with the new document. No reload.
Save to API route
// app/api/documents/route.ts
export async function POST(req: NextRequest) {
const data = await req.arrayBuffer();
// upload to S3, save to DB, etc.
return NextResponse.json({ ok: true });
}const saved = await editorRef.current?.save();
await fetch("/api/documents", { method: "POST", body: saved });Common errors
| Error | Fix |
|---|---|
| Styles not rendering | Import @eigenpal/docx-editor-react/styles.css in the client component |
Included features
The editor parses OOXML on the client and renders via ProseMirror. It supports bold/italic/underline, tables with cell merging, inline images, headers and footers, page breaks, tracked changes, threaded comments, zoom, and document outline. It exports back to valid .docx. Apache 2.0, ~200KB gzipped, no server dependency.
Next steps
- Next.js example on GitHub
- Track changes and comments for review workflows
- Document templates with variable placeholders
- React package docs for every prop, hook, and subpath
- Using Nuxt instead? See the Nuxt DOCX editor guide
- Full docs for all props and config