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
- Vue props
- Vue API reference
- React examples, identical patterns for cross-reference