Quickstart
Load, edit, and save a .docx in the browser in five minutes. Copy-paste setup for the open source DOCX editor in React and Vue, no backend needed.
One component, one stylesheet, no backend.
Install
Either adapter pulls in @eigenpal/docx-editor-core and @eigenpal/docx-editor-i18n transitively. One install is enough.
npm install @eigenpal/docx-editor-reactnpm install @eigenpal/docx-editor-vueOn Next.js, Remix, or other SSR frameworks the editor must render client-side. On Next.js, mounting it during SSR throws window is not defined; use the dynamic() recipe in Installation, which also covers the other frameworks. The code below works as-is in any client-rendered app.
Load, edit, save
The complete flow in one file. A file input feeds the editor, the editor handles all editing (typing, formatting, undo, tables, tracked changes), and a button serializes the current state back to a .docx download.
// App.tsx
import { useRef, useState } from 'react';
import { DocxEditor, type DocxEditorRef } from '@eigenpal/docx-editor-react';
import '@eigenpal/docx-editor-react/styles.css';
export default function App() {
const editorRef = useRef<DocxEditorRef>(null);
const [file, setFile] = useState<File | null>(null);
async function download() {
const buffer = await editorRef.current?.save();
if (!buffer) return;
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = file?.name ?? 'document.docx';
a.click();
URL.revokeObjectURL(url);
}
return (
<div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
<div style={{ padding: 8, display: 'flex', gap: 8 }}>
<input
type="file"
accept=".docx"
onChange={(e) => setFile(e.target.files?.[0] ?? null)}
/>
<button onClick={download}>Download .docx</button>
</div>
{file && <DocxEditor ref={editorRef} documentBuffer={file} mode="editing" />}
</div>
);
}<!-- App.vue -->
<script setup lang="ts">
import { ref } from 'vue';
import { DocxEditor, type DocxEditorRef } from '@eigenpal/docx-editor-vue';
import '@eigenpal/docx-editor-vue/styles.css';
const editorRef = ref<DocxEditorRef | null>(null);
const file = ref<File | null>(null);
function onPick(e: Event) {
file.value = (e.target as HTMLInputElement).files?.[0] ?? null;
}
async function download() {
const buffer = await editorRef.value?.save();
if (!buffer) return;
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = file.value?.name ?? 'document.docx';
a.click();
URL.revokeObjectURL(url);
}
</script>
<template>
<div style="height: 100vh; display: flex; flex-direction: column">
<div style="padding: 8px; display: flex; gap: 8px">
<input type="file" accept=".docx" @change="onPick" />
<button @click="download">Download .docx</button>
</div>
<DocxEditor v-if="file" ref="editorRef" :document-buffer="file" mode="editing" />
</div>
</template>Three things to know about this code:
documentBufferaccepts aFile,Blob,ArrayBuffer, orUint8Array. Pass theFilefrom the input directly; no manualarrayBuffer()step needed. Passnullto mount an empty document instead.save()on the editor ref returns aPromise<ArrayBuffer | null>: a complete.docx, ornullwhen there is no document to serialize (the code above guards for it). Parsing and serialization both happen in the browser; the document never touches a server.- The stylesheet import is required once per app. Without it the toolbar renders unstyled.
Fetch instead of file input (optional)
Loading a template from your own server is the same prop with a fetched buffer:
const buffer = await fetch('/template.docx').then((r) => r.arrayBuffer());
// <DocxEditor documentBuffer={buffer} />And if you'd rather react to the built-in Save action (Cmd+S or the toolbar button) instead of adding your own button, use the onSave prop, which receives the same ArrayBuffer:
<DocxEditor documentBuffer={file} onSave={(buffer) => upload(buffer)} />Open a real .docx from your machine
Run your dev server, click the file input, and pick any .docx you have lying around: a contract, a CV, a report with tables and headers. The editor parses it client-side, renders true Word-style pages, and the downloaded copy opens cleanly in Microsoft Word with formatting intact. That round trip is the whole point. If something renders wrong, file an issue with the document.
No file handy? Try the live demo first.
Next steps
- Installation for Next.js, Remix, Astro, and Nuxt specifics
- Production readiness if you're evaluating the library for adoption
- React props and ref methods for everything
<DocxEditor>can do - Agents to wire AI tools to the editor
Introduction
Open source WYSIWYG DOCX editor for React and Vue. Runs in the browser, no backend: .docx in, .docx out, with tracked changes, comments, and AI agents.
Quickstart: AI
Wire an AI assistant to the DOCX editor: one API route, one page. The agent reads the document, adds comments, and suggests tracked changes in the browser.