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 />} />

Use these root props to configure the packaged frame:

PropTypeDescription
titlestringDocument name shown in the title bar.
onTitleChange(title: string) => voidMakes the title editable.
renderTitleBarLeft / renderTitleBarRight() => ReactNodeHost-owned title bar slots.
menuboolean | DocxEditorMenuPropsToggle or customize the packaged menu row.
chromebooleanSet false to remove the packaged frame entirely.
navigationbooleanToggle the packaged navigation pane.
hyperlinkPopupbooleanToggle the packaged link popover.
contextMenuboolean | DocxEditorContextMenuPropsToggle 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>
  );
}

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>
  );
}

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 Esc to release it.
  • Press Ctrl+Alt+C to copy the formatting and Ctrl+Alt+V to apply it. On macOS, use Command in place of Ctrl.

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

On this page