TutorialMarch 18, 20262 min read

Vite DOCX editor: edit Word documents in a React and Vite app

Add a DOCX editor to a React + Vite project. Install the React adapter, load a .docx, edit it, and download the result.

To edit Word documents in a Vite app, install @docx-editor.dev/react, pass the document bytes, and render <DocxEditor>. Vite has no server and client module boundary, so the editor mounts without extra configuration.

Live demo

Open your own .docx, or edit the sample document in the demo. The demo does not upload anything. The document stays in your browser.

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

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>
  );
}

Vite needs no "use client" directive. It has no server and client module boundary, so the component mounts as it is.

Render the component

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

Let users open a file

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 backend

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("https://your-api.com/documents", {
      method: "POST",
      body: saved,
    });
  }
 
  return (
    <>
      <button onClick={save}>Save</button>
      <DocxEditor ref={editorRef} document={buffer} />
    </>
  );
}

save() returns Promise<ArrayBuffer | null>. It returns null when no document is open.

Common errors

ErrorFix
Styles do not renderImport @docx-editor.dev/core/styles/editor.css in your component
Blank editorLoad the ArrayBuffer before you render <DocxEditor>

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