Toolbar
Customize the editor chrome in React or Vue: keep the packaged toolbar and title bar, override a single slot, or compose your own from the parts.
The packaged host has two levels of chrome: a title bar (title, the title bar slots, and menu) and a formatting bar (the Toolbar part). Both the packaged host and the lower-level compounds live on the adapter package root.
Use the packaged chrome
Use the packaged host for the default chrome:
<DocxEditor document={bytes} title="Proposal.docx" renderTitleBarRight={() => <SaveIndicator />} /><DocxEditor :document="bytes" title="Proposal.docx">
<template #titleBarRight>
<SaveIndicator />
</template>
</DocxEditor>Use these root props to configure the packaged frame:
| Prop | Type | Description |
|---|---|---|
title | string | Document name shown in the title bar. |
onTitleChange | (title: string) => void | Makes the title editable. |
renderTitleBarLeft / renderTitleBarRight | () => ReactNode | Host-owned title bar slots. |
menu | boolean | DocxEditorMenuProps | Toggle or customize the packaged menu row. |
chrome | boolean | Set false to remove the packaged frame entirely. |
navigation | boolean | Toggle the packaged navigation pane. |
hyperlinkPopup | boolean | Toggle the packaged link popover. |
contextMenu | boolean | DocxEditorContextMenuProps | Toggle or customize the packaged context menu. |
| API | Type | Description |
|---|---|---|
title | string | Document name shown in the title bar. |
@title-change | (title: string) => void | Makes the title editable. |
#titleBarLeft / #titleBarRight | slot | Host-owned title bar slots. |
menu | boolean | DocxEditorMenuProps | Toggle or customize the packaged menu row. |
chrome | boolean | Set false to remove the packaged frame entirely. |
navigation | boolean | Toggle the packaged navigation pane. |
hyperlinkPopup | boolean | Toggle the packaged link popover. |
contextMenu | boolean | DocxEditorContextMenuProps | Toggle or customize the packaged context menu. |
Use the provider primitives
When you want your own frame, use the same provider primitives the packaged host uses internally:
import { DocxEditor } from '@docx-editor.dev/react';
function MyChrome({ bytes }: { bytes: Uint8Array }) {
return (
<DocxEditor.Root document={bytes}>
<DocxEditor.Toolbar />
<DocxEditor.Viewport>
<DocxEditor.Navigation />
<DocxEditor.Content />
<DocxEditor.HyperLink />
<DocxEditor.ContextMenu />
</DocxEditor.Viewport>
</DocxEditor.Root>
);
}<script setup lang="ts">
import {
DocxEditorContent,
DocxEditorContextMenu,
DocxEditorHyperLink,
DocxEditorNavigation,
DocxEditorRoot,
DocxEditorToolbar,
DocxEditorViewport,
} from '@docx-editor.dev/vue';
defineProps<{ bytes: Uint8Array }>();
</script>
<template>
<DocxEditorRoot :document="bytes">
<DocxEditorToolbar />
<DocxEditorViewport>
<DocxEditorNavigation />
<DocxEditorContent />
<DocxEditorHyperLink />
<DocxEditorContextMenu />
</DocxEditorViewport>
</DocxEditorRoot>
</template>The root owns the editor instance, the viewport is the scroll container, and the content part is the painted page surface. The other compounds layer on top of that same provider.
Add root-level command buttons
For small custom controls, call the shared command API from the package root:
import { useEditorCommand } from '@docx-editor.dev/react';
function BoldButton() {
const bold = useEditorCommand('text.bold');
return (
<button
onMouseDown={(e) => e.preventDefault()} // chrome must not steal the caret
onClick={() => bold.execute()}
disabled={!bold.isEnabled}
>
Bold
</button>
);
}<script setup lang="ts">
import { useEditorCommand } from '@docx-editor.dev/vue';
const bold = useEditorCommand('text.bold');
</script>
<template>
<!-- chrome must not steal the caret -->
<button @mousedown.prevent @click="bold.execute()" :disabled="!bold.isEnabled.value">Bold</button>
</template>useEditorCommand returns computed refs on a plain object, so read isEnabled,
isActive, and disabledReason with .value.
See the chrome slot reference for every slot, its packaged surface, and the matching React and Vue toolbar part.
Format painter
The format.painter slot copies the formatting at the selection and applies it somewhere
else. The text never moves.
- Click the control once to arm it for a single application, then select the text to format.
- Double-click the control to keep it on for repeated applications, and press
Escto release it. - Press
Ctrl+Alt+Cto copy the formatting andCtrl+Alt+Vto apply it. On macOS, useCommandin place ofCtrl.
On macOS, browsers bind Command+Option+C to their own element inspector, and a web page
can't override a browser shortcut. To copy formatting there, use the control or the
right-click menu. Command+Option+V applies the formatting as expected.
On Windows and Linux keyboard layouts that put characters on the AltGr level of C — for
example Polish — Ctrl+Alt+C types that character instead. Use the control or the
right-click menu.
- Right-click the document and choose Copy formatting or Paste formatting.
What the painter copies follows the selection. A selection inside one paragraph copies character formatting: font, size, color, and the character marks. A selection that covers the paragraph mark also copies the paragraph style, alignment, spacing, and indents.
The painter reads the formatting the reader sees, not only what the text states directly.
Copying from a paragraph that takes its face from a style carries that face to the target.
Three things stay on the target: paragraph borders (w:pBdr), a run's character style
(w:rStyle), and character shading (w:shd on a run).
To drive the painter from your own chrome, use the copyFormatting and pasteFormatting
commands. pasteFormatting reports a disabled reason until something is copied.
Table editing
When the caret or a rectangular cell selection is inside a table, the formatting toolbar shows contextual table controls:
- Resize: hover a column divider or the table's right edge; drag to commit Word-compatible twip widths (inner divider resize preserves total table width; outer-right resize changes table width).
- Insert rows/columns: hover the row band or column header band and click the
+control, or use the table rows on the right-click menu. - Borders and fill: with one or more cells selected, choose a border target, style, width, and color, then pick a cell fill (clear fill removes direct shading).
These controls target the innermost nested table under the pointer or selection. Merge and split remain unsupported; tables with merged cells refuse column resize/insert/delete with an explicit disabled reason.
The Igloo demo shows a custom toolbar order, custom icons, and two host actions. See the Igloo example source.
Next steps
Loading and saving
Load DOCX bytes into the editor root, swap documents through the shared ref, and serialize the current state back out to a .docx file on demand.
Chrome slot reference
Reference every editor chrome slot and its React and Vue toolbar part across default, contextual, menu, dialog, and header or footer surfaces.