Vue examples
Concrete patterns for the current Vue root surface: mount bytes, save through the ref, compose custom chrome, and automate an open editor.
Import @docx-editor.dev/vue/styles.css once in your application entry before
you use these examples.
Load DOCX bytes
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { DocxEditor } from '@docx-editor.dev/vue';
const doc = ref<Uint8Array>();
onMounted(() => {
void fetch('/template.docx')
.then((response) => response.arrayBuffer())
.then((buffer) => {
doc.value = new Uint8Array(buffer);
});
});
</script>
<template>
<DocxEditor :document="doc" title="Proposal.docx" />
</template>Save through the ref
<script setup lang="ts">
import { ref } from 'vue';
import { DocxEditor, type DocxEditorRef } from '@docx-editor.dev/vue';
const editorRef = ref<DocxEditorRef | null>(null);
async function save() {
const next = await editorRef.value?.save();
if (!next) return;
await fetch('/api/documents/42', { method: 'PUT', body: next });
}
</script>
<template>
<button @click="save">Save</button>
<DocxEditor ref="editorRef" :document="bytes" />
</template>Compose custom chrome
Create a button that reads the editor context:
<script setup lang="ts">
import { useEditorCommand } from '@docx-editor.dev/vue';
const bold = useEditorCommand('text.bold');
</script>
<template>
<button
@mousedown.prevent
:disabled="!bold.isEnabled.value"
:aria-pressed="bold.isActive.value"
:title="bold.disabledReason.value ?? 'Bold'"
@click="bold.execute()"
>
Bold
</button>
</template>Then place the button and editor parts under the root:
<script setup lang="ts">
import { DocxEditor } from '@docx-editor.dev/vue';
import BoldButton from './BoldButton.vue';
</script>
<template>
<DocxEditor.Root :document="bytes">
<DocxEditor.Toolbar>
<BoldButton />
</DocxEditor.Toolbar>
<DocxEditor.Viewport>
<DocxEditor.Navigation />
<DocxEditor.Content />
<DocxEditor.HyperLink />
<DocxEditor.ContextMenu />
</DocxEditor.Viewport>
</DocxEditor.Root>
</template>DocxEditor.Navigation shares the viewport with the document.
DocxEditor.HyperLink and DocxEditor.ContextMenu provide overlay chrome.
Automate an open editor
Render this component anywhere below DocxEditor.Root:
<script setup lang="ts">
import { useDocxEditor } from '@docx-editor.dev/vue';
import { DocxEditor as AutomationEditor } from '@docx-editor.dev/editor-api/browser';
const editor = useDocxEditor();
async function inspectFirstParagraph() {
if (!editor.value) return;
const runtime = AutomationEditor.createBrowser(editor.value);
try {
await runtime.run(async (context) => {
const first = context.document.body.paragraphs.getFirst();
first.load('text');
await context.sync();
console.log(first.text);
});
} finally {
runtime.dispose();
}
}
</script>
<template>
<button :disabled="!editor" @click="inspectFirstParagraph">Inspect first paragraph</button>
</template>Install @docx-editor.dev/editor-api before you use this example. The runtime
uses the editor that DocxEditor.Root created.
Fetch bytes and fonts together
<script setup lang="ts">
import {
DocxEditorRoot,
DocxEditorViewport,
DocxEditorContent,
useDocxSource,
} from '@docx-editor.dev/vue';
import { defaultFonts } from '@docx-editor.dev/fonts';
const { document, fonts, error, isLoading } = useDocxSource('/sample.docx', {
fonts: defaultFonts,
});
</script>
<template>
<DocxEditorRoot v-if="document" :document="document" :fonts="fonts">
<DocxEditorViewport>
<DocxEditorContent />
</DocxEditorViewport>
</DocxEditorRoot>
<p v-else-if="error">{{ error.message }}</p>
<p v-else-if="isLoading" aria-live="polite">Loading document</p>
</template>Live demo
The
examples/vue application
shows composition chrome, menu overrides, rulers, navigation, and package
build mode. Run it with bun run dev:vue.
The adapter parity demo serves React and Vue builds from
examples/parity/dist.
Next steps
- Vue composition: arrange editor parts.
- Vue composables: build reactive controls.
- Toolbar guide: find command slot IDs.
- Editing API: automate the open document.