To edit Word documents in a Next.js app, install @docx-editor.dev/react, pass the document bytes, and render <DocxEditor> inside a "use client" component. The editor parses Word OOXML in the browser.
This guide covers installation, the client component, file input handling, saving through a route handler, and the common server-side rendering (SSR) errors.
Live demo
This editor runs in this Next.js application. The demo sends no document data to a server.
Install
npm install @docx-editor.dev/react @docx-editor.dev/core@docx-editor.dev/core is a peer dependency. The adapter bundles the string catalog.
Build the editor component
"use client";
import { useState, useEffect, useRef, useCallback } from "react";
import { DocxEditor } from "@docx-editor.dev/react";
import type { DocxEditorRef } from "@docx-editor.dev/react";
import "@docx-editor.dev/core/styles/editor.css";
const DOCX_MIME =
"application/vnd.openxmlformats-officedocument.wordprocessingml.document";
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: DOCX_MIME });
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} document={buffer} mode="edit" />
<button onClick={handleSave}>Download .docx</button>
</div>
);
}Add "use client". The component uses refs, hooks, and browser globals, so it cannot render on the server.
Render the component in a page
import { MyDocxEditor } from "@/components/DocxEditor";
export default function EditorPage() {
return <MyDocxEditor />;
}Let users open a file
"use client";
import { useState } from "react";
import { DocxEditor } from "@docx-editor.dev/react";
export function UploadEditor() {
const [buffer, setBuffer] = useState<ArrayBuffer | null>(null);
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);
}
return (
<div style={{ height: "80vh" }}>
<input type="file" accept=".docx" onChange={handleUpload} />
{buffer && <DocxEditor document={buffer} />}
</div>
);
}Set a different buffer to load another document without a page reload.
Save to a route handler
// app/api/documents/route.ts
import { NextResponse, type NextRequest } from "next/server";
export async function POST(request: NextRequest) {
const data = await request.arrayBuffer();
// Store the bytes: upload to object storage, write to a database, and so on.
console.log(`received ${data.byteLength} bytes`);
return NextResponse.json({ ok: true });
}"use client";
import { useRef } from "react";
import { DocxEditor, type DocxEditorRef } from "@docx-editor.dev/react";
export function SavingEditor({ buffer }: { buffer: ArrayBuffer }) {
const editorRef = useRef<DocxEditorRef>(null);
async function save() {
const saved = await editorRef.current?.save();
if (!saved) return;
await fetch("/api/documents", { method: "POST", body: saved });
}
return (
<>
<button onClick={save}>Save</button>
<DocxEditor ref={editorRef} document={buffer} />
</>
);
}Common errors
| Error | Fix |
|---|---|
| Styles do not render | Import @docx-editor.dev/core/styles/editor.css in the client component |
Included features
The editor parses OOXML in the browser and renders the document as pages. It supports:
- Bold, italic, underline, and strikethrough
- Tables, including merged cells
- Inline and floating images
- Headers, footers, and page breaks
- Zoom and a document outline
It writes the document back to .docx. The editor is Apache 2.0 and needs no document-processing server. For more information about tracked changes, comments, and custom nodes, see the Pro module.
Where to go next
- React DOCX viewer covers document preview and Word-faithful rendering.
- Next.js setup reference covers the same steps in the docs.
- Next.js example on GitHub is a runnable project.
- Tracked changes and Comments cover review workflows.
- React package overview describes the full surface.
- Nuxt DOCX editor covers the Vue equivalent.
- React props reference documents every prop.