Vue

Props

DocxEditorProps for the Vue 3 adapter: the shared prop shape, Vue's kebab-case binding, named slots, and the events the component emits.

The Vue adapter accepts the paired subset of the React props; the differences are Vue's kebab-case attribute binding, named slots and emitted events in place of some render props and callbacks, and a few React-only props that Vue defers (listed below). Anything in the paired bucket of the parity contract behaves exactly as documented under React props. Full generated reference: /docs/1.x/api/vue.

Binding props

Camel-case in TS, kebab-case in the template. Bind with : for non-string values:

<script setup lang="ts">
import { ref } from 'vue';
import { DocxEditor, type EditorMode } from '@eigenpal/docx-editor-vue';
import '@eigenpal/docx-editor-vue/styles.css';

const buf = ref<ArrayBuffer | null>(null);
const mode = ref<EditorMode>('editing');
</script>

<template>
  <DocxEditor
    :document-buffer="buf"
    :mode="mode"
    author="Jess Lin"
    :show-zoom-control="true"
    @mode-change="(m) => (mode = m)"
  />
</template>

Props that are React callbacks become Vue events. So onModeChange in React is @mode-change in Vue. Same payload shape.

Template ref

Capture the editor ref with useTemplateRef (Vue 3.5+) or ref="..." + a ref():

<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(); // Promise<ArrayBuffer | null>
  if (buf) await fetch('/api/documents/1', { method: 'PUT', body: buf });
}
</script>

<template>
  <button @click="save">Save</button>
  <DocxEditor ref="editor" :document-buffer="null" />
</template>

Methods on DocxEditorRef match React one-to-one (save, addComment, proposeChange, findInDocument, scrollToParaId, scrollToPosition, getDocument, and the rest). See React props for the signature table.

Props by group

The paired groups under React props apply identically. Quick map of the binding syntax for each group, plus the Vue-specific differences.

Document input

<DocxEditor :document-buffer="buf" />
<!-- or, pre-parsed -->
<DocxEditor :document="parsed" />

document-buffer accepts the same DocxInput union as React (File, Blob, ArrayBuffer, Uint8Array), so a File from an <input type="file" accept=".docx"> binds directly.

Mode and read-only

<DocxEditor :document-buffer="buf" :mode="mode" @mode-change="(m) => (mode = m)" />
<DocxEditor :document-buffer="buf" read-only />

Comments and collaboration

The Vue adapter has no controlled comments prop (it is React-only, listed as deferred in the parity contract). Comment state lives inside the editor; observe mutations through @comments-change and the granular comment events, and create comments imperatively through the ref:

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

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="Jess Lin" @comments-change="persist" />
</template>

To add 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.

Toolbar UI

<DocxEditor
  :document-buffer="buf"
  :show-toolbar="false"
  :show-zoom-control="false"
  :initial-zoom="1.25"
/>

Vue also has :show-menu-bar (default true) for the menu bar above the toolbar; React has no menu-bar concept. :show-help-menu (default true) controls Help menu visibility; set false to hide it, matching React's showHelpMenu. The React-only toolbar/layout props showMarginGuides, marginGuideColor, and rulerUnit are not available in Vue.

Appearance (dark mode)

:color-mode ('light' | 'dark' | 'system', default 'light') sets the editor theme; 'system' follows the OS prefers-color-scheme. There is no internal toggle; drive it from your own UI by binding a ref:

<script setup>
import { ref } from 'vue';
const colorMode = ref('light');
</script>

<template>
  <button @click="colorMode = colorMode === 'dark' ? 'light' : 'dark'">Toggle theme</button>
  <DocxEditor :document-buffer="buf" :color-mode="colorMode" />
</template>

Behaviour matches React. See the Dark mode guide for the full details.

Fonts

:fonts registers custom font faces and :font-families constrains the picker; the full rules (FontDefinition shape, weights, stable references, error routing) are under React props → Fonts and apply unchanged.

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

const fonts = [
  { family: 'Custom Sans', src: '/fonts/CustomSans-Regular.woff2' },
  { family: 'Custom Sans', src: '/fonts/CustomSans-Bold.woff2', weight: 700 },
];
</script>

<template>
  <DocxEditor
    :document-buffer="buf"
    :fonts="fonts"
    :font-families="['Custom Sans', 'Arial']"
  />
</template>

Keep the array reference stable (declared once in setup, not rebuilt inline). Font-load failures surface through the @error event; with no listener attached they fall back to console.warn. Note that React's onFontsLoaded callback has no Vue equivalent yet.

Title bar slots

Vue exposes three named slots: title-bar-left, title-bar-right, and toolbar-extra.

<DocxEditor :document-buffer="buf" document-name="Q3 Memo">
  <template #title-bar-left>
    <img src="/logo.svg" alt="Logo" width="24" height="24" />
  </template>
  <template #title-bar-right>
    <SaveIndicator :dirty="dirty" />
  </template>
  <template #toolbar-extra>
    <button @click="wordCount">Word count</button>
  </template>
</DocxEditor>

Mapping from the React render props: renderLogo#title-bar-left, renderTitleBarRight#title-bar-right, toolbarExtra#toolbar-extra. The renderLogo / renderTitleBarRight props also exist on the Vue component as render functions if you prefer props over slots.

Callbacks and events

The component emits these events:

EventPayloadFires when
@changeDocumentAny document mutation.
@update:documentDocument | nullThe parsed document changes (pairs with v-model:document style usage).
@errorErrorParse, render, or font-load errors.
@readynoneThe editor finished mounting.
@renamestringThe user edits the document name in the title bar.
@menu-actionstringA menu-bar action is triggered.
@mode-changeEditorModeThe editing mode changes.

These React callbacks are also available as props, so the @kebab-case listener syntax works for them too:

React propVue listener
onSelectionChange@selection-change
onCommentsChange@comments-change
onCommentAdd / onCommentResolve / onCommentDelete / onCommentReply@comment-add / @comment-resolve / @comment-delete / @comment-reply
onDocumentNameChange@document-name-change
onEditorViewReady@editor-view-ready
onPrint@print

There is no @save, @fonts-loaded, @copy, @cut, or @paste in Vue. For saving, call save() on the template ref; for clipboard hooks, use the useClipboard composable from /composables.

<DocxEditor
  :document-buffer="buf"
  @change="onChange"
  @error="reportError"
  @ready="onReady"
/>

Customize File > Open

Like React, the built-in File > Open item and Cmd/Ctrl+O load a picked .docx into the local editor. Pass on-open to keep the native file picker but route the selected File through your own import pipeline, and :show-file-open="false" to hide the built-in item (Cmd/Ctrl+O is then left for your own menu or toolbar):

<DocxEditor
  :document="doc"
  :external-plugins="plugins"
  :show-file-open="false"
  :on-open="(file) => importIntoBackend(file)"
/>

on-open is useful when a collaborative binding owns the document state. Omit it to keep the built-in local load.

Styling

<DocxEditor
  :document-buffer="buf"
  class="rounded-lg shadow-md"
  :style="{ height: '80vh' }"
/>

The React-only placeholder and loadingIndicator props have no Vue equivalent; there is no #placeholder slot.

i18n

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

<template>
  <DocxEditor :document-buffer="buf" :i18n="pl" />
</template>

Agents

The React agentPanel prop has no Vue equivalent (deferred in the parity contract), and there is no #agentPanel slot. Wire the agent toolkit with the useAgentBridge composable and render your 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';

const editor = useTemplateRef<DocxEditorRef>('editor');
const { executeToolCall, toolSchemas } = useAgentBridge({
  editorRef: editor,
  author: 'Assistant',
});
</script>

<template>
  <div style="display: flex">
    <DocxEditor ref="editor" :document-buffer="buf" />
    <!-- your chat pane next to the editor -->
  </div>
</template>

Full agent wiring in Agents → Live editor.

Next steps

On this page