New

docx-editor 1.x has shipped. Vue support, i18n, agents. Read the migration guide →

TutorialMay 20, 2026·2 min read

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

Edit DOCX files in your Next.js app with an open-source, client-side Word document editor. Embed the editor with no server and no upload. Includes a live interactive demo.

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, so you can embed a full Word document editor with no server and no file upload. This post covers install, the client component, file uploads, saving to an API route, and the common errors.

Live demo

This editor runs in the Next.js app you're reading right now. Upload a .docx or edit the sample below. Nothing leaves your 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

What you get

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