docx-editor 1.x has shipped. Vue support, i18n, agents.

Migration guide →
TutorialMay 20, 20262 min read

Next.js DOCX Editor: Edit and Embed Word Documents in the Browser

Edit DOCX files in a Next.js App Router project. Install the React adapter, render it client-side, load a file, and save the result.

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-react

Editor 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

ErrorFix
Styles not renderingImport @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