Open-source WYSIWYG .docx editor for React and Vue. Word-faithful pagination, tracked changes, comments, and lossless round-trip: untouched content and unsupported OOXML survive the save. Live demo | Documentation
npm install @docx-editor.dev/react @docx-editor.dev/core # React
npm install @docx-editor.dev/vue @docx-editor.dev/core # Vue
See the React or Vue quick start below.
| Package | Description | Docs |
|---|---|---|
@docx-editor.dev/react |
Docs | |
@docx-editor.dev/vue |
Docs | |
@docx-editor.dev/core |
Framework-agnostic engine: OOXML read/write, canonical document tree, layout, paint. Depend on this if you fork an adapter. | Docs |
@docx-editor.dev/i18n |
Shared locale strings and types consumed by the adapter. | Docs |
@docx-editor.dev/pro |
Tracked changes, comments, and custom nodes. | Docs |
@docx-editor.dev/editor-api |
Office.js-compatible editing API: a batching object model that edits a document from a server, or an editor already open in a page. | Docs |
Every package above is Apache 2.0 except @docx-editor.dev/editor-api and @docx-editor.dev/pro, which are licensed under the EigenPal Pro Evaluation License 1.0 (editor-api, pro): free to evaluate, production use requires a commercial agreement — licensing@eigenpal.com.
Forking the adapter? Keep your fork thin. Depend on
@docx-editor.dev/coredirectly so parser, serializer, and rendering fixes land in your build automatically, without backporting each upstream change by hand.
import { useState } from 'react';
import { DocxEditor } from '@docx-editor.dev/react';
import '@docx-editor.dev/core/styles/editor.css';
export function App() {
const [doc, setDoc] = useState<Uint8Array>();
return (
<div style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
<input
type="file"
accept=".docx"
onChange={async (e) => {
const file = e.target.files?.[0];
setDoc(file ? new Uint8Array(await file.arrayBuffer()) : undefined);
}}
/>
<div style={{ flex: 1, minHeight: 0 }}>
{doc && <DocxEditor document={doc} mode="edit" />}
</div>
</div>
);
}
Next.js / SSR: Use dynamic import. The editor requires the DOM.
Full docs: React adapter · Props and ref methods.
<script setup lang="ts">
import { ref } from 'vue';
import { DocxEditor } from '@docx-editor.dev/vue';
import '@docx-editor.dev/vue/styles.css';
const doc = ref<Uint8Array>();
async function onPick(event: Event) {
const file = (event.target as HTMLInputElement).files?.[0];
doc.value = file ? new Uint8Array(await file.arrayBuffer()) : undefined;
}
</script>
<template>
<div style="height: 100vh; display: flex; flex-direction: column">
<input type="file" accept=".docx" @change="onPick" />
<div style="flex: 1; min-height: 0">
<DocxEditor v-if="doc" :document="doc" mode="edit" />
</div>
</div>
</template>
Nuxt / SSR: Load the editor in a client-only component. The editor requires the DOM.
Full docs: Vue adapter · Props and ref methods.
bun install
bun run dev # localhost:5173
bun run build
bun run typecheck
A live preview of main is auto-deployed at latest.docx-editor.dev — useful for trying out changes before they ship to npm.
Examples: Vite | Next.js | Remix | Astro | Vue
Documentation | React props & ref methods | Vue props & ref methods
Contributions welcome. See CONTRIBUTING.md for setup, tests, and the one-time CLA signature.
| Locale | Language |
|---|---|
en |
English |
de |
German |
fr |
French |
he |
Hebrew |
hi |
Hindi |
id |
Indonesian |
pl |
Polish |
pt-BR |
Portuguese (Brazil) |
tr |
Turkish |
zh-CN |
Chinese (Simplified) |
Help translate the editor into your language! See the full i18n contribution guide.
bun run i18n:new de # scaffold German locale
bun run i18n:status # check translation coverage
Apache 2.0, except packages/editor-api/ and packages/pro/, which are licensed under the EigenPal Pro Evaluation License 1.0 (editor-api, pro). That licence permits internal, non-production evaluation; production use requires a written commercial agreement, available from licensing@eigenpal.com.
[!TIP] Questions or custom features? Email docx-editor@eigenpal.com.