New

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

Vue

Vue Examples

Concrete patterns for embedding <DocxEditor> in Vue 3: load from URL, controlled comments, autosave, Yjs collaboration, agent panel.

Drop-in components for the common patterns. Each is self-contained; swap the data source for your own.

Load a document 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>

Load from a file input

<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>

Autosave on change

<script setup lang="ts">
import { useTemplateRef } from "vue";
import { DocxEditor, type DocxEditorRef } from "@eigenpal/docx-editor-vue";
 
const props = defineProps<{ docId: string }>();
const editor = useTemplateRef<DocxEditorRef>("editor");
 
let timer: number | null = null;
function onChange() {
  if (timer !== null) window.clearTimeout(timer);
  timer = window.setTimeout(async () => {
    const buf = await editor.value?.save();
    if (!buf) return;
    await fetch(`/api/documents/${props.docId}`, { method: "PUT", body: buf });
  }, 1500);
}
</script>
 
<template>
  <DocxEditor ref="editor" :document-buffer="null" @change="onChange" />
</template>

Controlled comments

<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[]>([]);
 
async function persist(next: Comment[]) {
  comments.value = next;
  await fetch("/api/comments", {
    method: "PUT",
    body: JSON.stringify(next),
    headers: { "content-type": "application/json" },
  });
}
</script>
 
<template>
  <DocxEditor
    :document-buffer="buf"
    :author="author"
    :comments="comments"
    @comments-change="persist"
  />
</template>

Suggesting mode

<script setup lang="ts">
import { ref } from "vue";
import { DocxEditor, type EditorMode } from "@eigenpal/docx-editor-vue";
 
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>

Read-only viewer

<script setup lang="ts">
import { DocxEditor } from "@eigenpal/docx-editor-vue";
 
defineProps<{ buf: ArrayBuffer }>();
</script>
 
<template>
  <DocxEditor
    :document-buffer="buf"
    read-only
    :show-toolbar="false"
    :show-zoom-control="false"
  />
</template>

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";
import type { Comment } from "@eigenpal/docx-editor-core";
 
defineProps<{ buf: ArrayBuffer }>();
const ydoc = new Y.Doc();
const provider = new WebrtcProvider("room-1", ydoc);
const yXml = ydoc.getXmlFragment("docx");
const yComments = ydoc.getArray<Comment>("comments");
 
const plugins = [ySyncPlugin(yXml), yCursorPlugin(provider.awareness), yUndoPlugin()];
const comments = ref<Comment[]>(yComments.toArray());
 
yComments.observe(() => {
  comments.value = yComments.toArray();
});
 
function onCommentsChange(next: Comment[]) {
  ydoc.transact(() => {
    yComments.delete(0, yComments.length);
    yComments.push(next);
  });
}
 
onUnmounted(() => provider.destroy());
</script>
 
<template>
  <DocxEditor
    :document-buffer="buf"
    :external-plugins="plugins"
    :comments="comments"
    @comments-change="onCommentsChange"
  />
</template>

Full provider walkthrough (y-webrtc, PartyKit, Liveblocks) on Realtime collaboration.

Agent panel

<script setup lang="ts">
import { useTemplateRef } from "vue";
import { DocxEditor, type DocxEditorRef } from "@eigenpal/docx-editor-vue";
import {
  AgentChatLog,
  AgentComposer,
  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 #agentPanel>
      <AgentChatLog :messages="chat.messages" />
      <AgentComposer @submit="chat.sendMessage" />
    </template>
  </DocxEditor>
</template>

Server-side route + setup in Agents → Live editor.

See also