TutorialMarch 18, 2026·1 min read

Vite DOCX Editor: Edit Word Documents in a React + Vite App

Add a browser-based DOCX editor to your Vite project. Open, edit, and save Word documents client-side with zero server dependency. Includes live demo and full code.

Live demo

Upload a .docx or edit the sample below. Nothing leaves your browser.

Install

npm install @eigenpal/docx-js-editor

Editor component

import { useState, useEffect, useRef, useCallback } from "react";
import { DocxEditor } from "@eigenpal/docx-js-editor";
import type { DocxEditorRef } from "@eigenpal/docx-js-editor";
import "@eigenpal/docx-js-editor/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>
  );
}

No "use client" directive needed. Vite has no server/client module boundary.

Use it in your app

import { MyDocxEditor } from "./components/DocxEditor";
 
function App() {
  return <MyDocxEditor />;
}
 
export default App;

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. No reload.

Save to a backend

const saved = await editorRef.current?.save();
await fetch("https://your-api.com/documents", {
  method: "POST",
  body: saved,
});

save() returns a raw ArrayBuffer.

Common errors

ErrorFix
Styles not renderingImport @eigenpal/docx-js-editor/styles.css in your component
Blank editorEnsure the ArrayBuffer is loaded before rendering <DocxEditor>

What you get

The editor parses OOXML on the client and renders via ProseMirror. Out of the box: 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. MIT licensed, ~200KB gzipped, no server dependency.

Next steps