New

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

TutorialMay 19, 2026·4 min read

Vue DOCX Editor: Edit Word Documents in Vue 3

Add a full-featured DOCX (Word document) editor to your Vue 3 app with @eigenpal/docx-editor-vue. Client-side, no server, no upload. Open source, Apache 2.0. With a live interactive demo.

The fastest way to put a Word document editor into a Vue 3 app: install @eigenpal/docx-editor-vue, pass an ArrayBuffer, render <DocxEditor>. Nothing leaves the browser. No backend, no document upload, no Office Online iframe. This post covers install, loading and saving .docx, Nuxt, tracked changes, comments, realtime collaboration, and AI agents.

Live demo

Install

npm install @eigenpal/docx-editor-vue

The package pulls @eigenpal/docx-editor-core and @eigenpal/docx-editor-i18n transitively. One install for the editor; add @eigenpal/docx-editor-agents if you want the AI agent toolkit on top.

Render <DocxEditor> in Vue 3

<script setup lang="ts">
import { ref } from "vue";
import { DocxEditor } from "@eigenpal/docx-editor-vue";
import "@eigenpal/docx-editor-vue/styles.css";
 
const buf = ref<ArrayBuffer | null>(null);
</script>
 
<template>
  <DocxEditor :document-buffer="buf" />
</template>

That's a working WYSIWYG Word document editor in your Vue 3 app. null mounts an empty document. Pass an ArrayBuffer to load a .docx file.

Load a .docx file

From a URL:

<script setup lang="ts">
import { ref, watchEffect } from "vue";
import { DocxEditor } from "@eigenpal/docx-editor-vue";
import "@eigenpal/docx-editor-vue/styles.css";
 
const props = defineProps<{ url: string }>();
const buf = ref<ArrayBuffer | null>(null);
 
watchEffect(async () => {
  buf.value = await fetch(props.url).then((r) => r.arrayBuffer());
});
</script>
 
<template>
  <DocxEditor :document-buffer="buf" />
</template>

From a file picker:

<script setup lang="ts">
import { ref } from "vue";
import { DocxEditor } from "@eigenpal/docx-editor-vue";
 
const buf = ref<ArrayBuffer | null>(null);
 
async function onFile(e: Event) {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (file) buf.value = await file.arrayBuffer();
}
</script>
 
<template>
  <input type="file" accept=".docx" @change="onFile" />
  <DocxEditor v-if="buf" :document-buffer="buf" />
</template>

The editor parses OOXML in the browser. No server round-trip, no file upload.

Save a .docx file

<script setup lang="ts">
import { useTemplateRef } from "vue";
import { DocxEditor, type DocxEditorRef } from "@eigenpal/docx-editor-vue";
 
const editor = useTemplateRef<DocxEditorRef>("editor");
 
async function save() {
  const buf = await editor.value?.save();
  if (!buf) return;
  // Trigger a browser download:
  const blob = new Blob([buf], {
    type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  });
  const a = Object.assign(document.createElement("a"), {
    href: URL.createObjectURL(blob),
    download: "edited.docx",
  });
  a.click();
  URL.revokeObjectURL(a.href);
}
</script>
 
<template>
  <button @click="save">Download .docx</button>
  <DocxEditor ref="editor" :document-buffer="null" />
</template>

save() returns an ArrayBuffer of OOXML bytes. Same format the editor reads. The round-trip is lossless: open a Word document, edit, save, reopen in Word, no fidelity loss.

Nuxt

For Nuxt 3 and 4, install @eigenpal/nuxt-docx-editor, the official Nuxt module. It wraps this adapter and auto-imports an SSR-safe <DocxEditor>, so you skip the <ClientOnly> wrapper and the Vite config:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ["@eigenpal/nuxt-docx-editor"],
});

<DocxEditor> is then available in any page or component with no import, and the stylesheet is injected for you. The Nuxt DOCX editor guide walks through the full setup.

What's included

  • Round-trip fidelity. Open a Word .docx, edit, save, reopen in Word. Tables, headers, footers, footnotes, images, tracked changes, comments, page layout. No quality loss.
  • Tracked changes. Suggesting mode wraps every edit as a revision marker with author attribution. Accept or reject individually or in bulk.
  • Comments. Threaded comments anchored to text ranges. Add, reply, resolve, delete.
  • Realtime collaboration. Wire to a Yjs document to get live multi-user editing with cursors and presence. Works with y-webrtc (zero infra), PartyKit, Liveblocks, or any Yjs provider.
  • Document templates. A templatePlugin highlights {{variable}} placeholders. Fill them programmatically or through the built-in panel.
  • Plugins. Extensible architecture with ProseMirror plugins for custom toolbar actions, keyboard shortcuts, document transformations.
  • i18n. Built-in localization for English, Polish, German, Brazilian Portuguese, Hebrew, Turkish, Simplified Chinese, with per-locale code-splitting.

Tracked changes in Vue

<script setup lang="ts">
import { ref } from "vue";
import { DocxEditor, type EditorMode } from "@eigenpal/docx-editor-vue";
 
const props = defineProps<{ buf: ArrayBuffer; reviewer: string }>();
const mode = ref<EditorMode>("suggesting");
</script>
 
<template>
  <DocxEditor
    :document-buffer="buf"
    :author="reviewer"
    :mode="mode"
    @mode-change="(m) => (mode = m)"
  />
</template>

Edits made in "suggesting" mode wrap as tracked changes with reviewer as the author. The document owner can accept or reject them later.

Comments in Vue

<script setup lang="ts">
import { ref } from "vue";
import { DocxEditor } from "@eigenpal/docx-editor-vue";
import type { Comment } from "@eigenpal/docx-editor-core";
 
defineProps<{ buf: ArrayBuffer; author: string }>();
const comments = ref<Comment[]>([]);
</script>
 
<template>
  <DocxEditor
    :document-buffer="buf"
    :author="author"
    :comments="comments"
    @comments-change="(next) => (comments = next)"
  />
</template>

Controlled comments mean you own the source of truth. Mirror comments into a Y.Array on a shared Yjs doc and you get live comment sync across users.

Realtime collaboration (Yjs)

<script setup lang="ts">
import { ref, onUnmounted } from "vue";
import * as Y from "yjs";
import { WebrtcProvider } from "y-webrtc";
import { ySyncPlugin, yCursorPlugin, yUndoPlugin } from "y-prosemirror";
import { DocxEditor } from "@eigenpal/docx-editor-vue";
 
defineProps<{ buf: ArrayBuffer }>();
const ydoc = new Y.Doc();
const provider = new WebrtcProvider("room-1", ydoc);
const yXml = ydoc.getXmlFragment("docx");
 
const plugins = [
  ySyncPlugin(yXml),
  yCursorPlugin(provider.awareness),
  yUndoPlugin(),
];
 
onUnmounted(() => provider.destroy());
</script>
 
<template>
  <DocxEditor
    :document-buffer="buf"
    :external-plugins="plugins"
  />
</template>

Live cursors, presence, conflict-free merging across browsers. Works against any Yjs provider, so you can pick the infrastructure model that fits.

AI agents driving the editor

@eigenpal/docx-editor-agents/vue exposes the agent toolkit as a Vue composable. The 14 tools (read, find, comment, suggest, scroll) drive the editor live; the agent's comments and tracked changes land as the model streams tokens.

<script setup lang="ts">
import { useTemplateRef } from "vue";
import { DocxEditor, type DocxEditorRef } from "@eigenpal/docx-editor-vue";
import { useDocxAgentTools } from "@eigenpal/docx-editor-agents/vue";
import { useChat } from "@ai-sdk/vue";
 
defineProps<{ buf: ArrayBuffer }>();
const editor = useTemplateRef<DocxEditorRef>("editor");
const { tools } = useDocxAgentTools({ editorRef: editor });
const chat = useChat({ api: "/api/agent-chat", body: { tools } });
</script>
 
<template>
  <DocxEditor ref="editor" :document-buffer="buf" />
</template>

Server-side route uses getAiSdkTools() from @eigenpal/docx-editor-agents/ai-sdk/server and any OpenAI / Anthropic / Vercel-AI-SDK-compatible model.

Open source, Apache 2.0

@eigenpal/docx-editor-vue is open source under Apache 2.0. Use it in personal and commercial projects, modify the source, redistribute. No usage limits, no watermarks, no premium tier. The source lives at github.com/eigenpal/docx-editor in packages/vue/.

Comparison to other Vue Word editors

The Vue ecosystem has had a thin selection of .docx editors. Most options either:

  • Render to HTML and lose OOXML fidelity (no tables-of-contents, no page layout, no tracked changes when round-tripped).
  • Are SaaS components with server-side processing (your documents touch their servers).
  • Are React libraries with a Vue wrapper (extra bundle, extra hydration cost).

@eigenpal/docx-editor-vue is a published Vue 3 adapter built on a shared core. Same OOXML parser as the React adapter, same plugin contract, no wrapper. Editing happens entirely client-side. Documents never leave the browser unless you explicitly upload them.

Where to next