Vue

Vue examples

Concrete patterns for embedding <DocxEditor> in Vue 3: load from URL or file input, autosave, comment persistence, custom fonts, read-only viewer, agent chat.

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

document-buffer accepts a File directly, so there is no arrayBuffer() step:

<script setup lang="ts">
import { ref } from 'vue';
import { DocxEditor } from '@eigenpal/docx-editor-vue';

const file = ref<File | null>(null);

function onFile(e: Event) {
  file.value = (e.target as HTMLInputElement).files?.[0] ?? null;
}
</script>

<template>
  <input type="file" accept=".docx" @change="onFile" />
  <DocxEditor v-if="file" :document-buffer="file" />
</template>

Autosave on change

Debounce save() on the template ref to persist to a server:

<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 | undefined;
function onChange() {
  window.clearTimeout(timer);
  timer = window.setTimeout(async () => {
    const buf = await editor.value?.save(); // Promise<ArrayBuffer | null>
    if (buf) await fetch(`/api/documents/${props.docId}`, { method: 'PUT', body: buf });
  }, 1500);
}
</script>

<template>
  <DocxEditor ref="editor" :document-buffer="null" @change="onChange" />
</template>

For localStorage autosave with crash recovery, use the useAutoSave composable from @eigenpal/docx-editor-vue/composables instead.

Persisting comments

The Vue adapter has no controlled comments prop (React-only; see Vue props). Listen to @comments-change to persist comment state as it mutates:

<script setup lang="ts">
import { DocxEditor } from '@eigenpal/docx-editor-vue';
import type { Comment } from '@eigenpal/docx-editor-core';

defineProps<{ buf: ArrayBuffer; author: string }>();

async function persist(next: Comment[]) {
  await fetch('/api/comments', {
    method: 'PUT',
    body: JSON.stringify(next),
    headers: { 'content-type': 'application/json' },
  });
}
</script>

<template>
  <DocxEditor :document-buffer="buf" :author="author" @comments-change="persist" />
</template>

To create a comment from your own UI, call editor.value?.addComment({ paraId, text, author }) on the template ref. Pushing an external comment array into the editor is not possible in Vue today.

Suggesting mode

<script setup lang="ts">
import { DocxEditor } from '@eigenpal/docx-editor-vue';

defineProps<{ buf: ArrayBuffer; reviewer: string }>();
</script>

<template>
  <DocxEditor :document-buffer="buf" :author="reviewer" mode="suggesting" />
</template>

Edits wrap in revision markup and round-trip to Word's <w:ins> / <w:del>; since 1.1.0 this covers paragraph, table, image, and list changes as well as inline text. See Tracked changes.

Custom fonts

:fonts registers self-hosted font faces and :font-families controls the picker; the full rules are under React props → Fonts.

<script setup lang="ts">
import { DocxEditor } from '@eigenpal/docx-editor-vue';

defineProps<{ buf: ArrayBuffer }>();

// Declared once in setup so the array identity stays stable.
const fonts = [
  { family: 'Inter', src: '/fonts/Inter-Regular.woff2' },
  { family: 'Inter', src: '/fonts/Inter-Bold.woff2', weight: 700 },
  { family: 'JetBrains Mono', src: '/fonts/JetBrainsMono-Regular.woff2' },
];
const fontFamilies = ['Inter', 'JetBrains Mono', 'Arial', 'Times New Roman'];
</script>

<template>
  <DocxEditor
    :document-buffer="buf"
    :fonts="fonts"
    :font-families="fontFamilies"
    @error="(err) => console.error('font or parse error', err)"
  />
</template>

The /fonts/... paths resolve against your site root (public/ in Vite or a Nuxt app).

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)

The Vue adapter ships :external-plugins for the y-prosemirror plugins, but the two other pieces of the collaboration setup are React-only today: the externalContent loader hand-off and the controlled comments prop (both listed as deferred in the parity contract). The full Yjs walkthrough on Realtime collaboration is therefore written against the React adapter; follow it there if you need live multi-user editing now.

Agent chat next to the editor

Vue exposes the agent toolkit through the useAgentBridge composable. There is no agentPanel prop or slot in the Vue adapter (React-only for now), so render the chat UI beside the editor:

<script setup lang="ts">
import { useTemplateRef } from 'vue';
import { DocxEditor, type DocxEditorRef } from '@eigenpal/docx-editor-vue';
import { useAgentBridge } from '@eigenpal/docx-editor-agents/vue';

defineProps<{ buf: ArrayBuffer }>();
const editor = useTemplateRef<DocxEditorRef>('editor');
const { executeToolCall, toolSchemas } = useAgentBridge({
  editorRef: editor,
  author: 'Assistant',
});
// Send toolSchemas to your LLM route; run each returned tool call through
// executeToolCall(name, input) and feed the result back to the model.
</script>

<template>
  <div class="layout">
    <DocxEditor ref="editor" :document-buffer="buf" />
    <!-- your chat pane: AgentChatLog / AgentComposer from
         @eigenpal/docx-editor-agents/vue, or your own UI -->
  </div>
</template>

Full tool loop (server route, streaming, AI SDK wiring) in AI document editing; the Vue specifics are in Agents → Live editor.

Next steps

On this page