Composition

Build a custom Vue PPTX editor from the root, the viewport, the content, and compound parts.

<PptxEditor> is a packaged arrangement of public components. Compose those components yourself when you need a different layout or your own controls.

Compose an editor

This example mounts a toolbar, the slide rail, the canvas, and the notes in a bounded column:

<script setup lang="ts">
import {
  PptxEditorContent,
  PptxEditorEditNotice,
  PptxEditorFindBar,
  PptxEditorFontNotice,
  PptxEditorLoading,
  PptxEditorNotesPane,
  PptxEditorOpenFailure,
  PptxEditorRoot,
  PptxEditorSlideRail,
  PptxEditorSlideshow,
  PptxEditorToolbar,
  PptxEditorViewport,
} from '@pptx-editor.dev/vue';
import '@pptx-editor.dev/vue/styles.css';

defineProps<{ bytes: Uint8Array }>();
</script>

<template>
  <div style="height: 100vh">
    <PptxEditorRoot :document="bytes">
      <PptxEditorViewport class="deck-workspace">
        <PptxEditorToolbar />
        <div class="deck-workspace__body">
          <PptxEditorSlideRail />
          <div class="deck-workspace__main">
            <PptxEditorContent />
            <PptxEditorFindBar />
            <PptxEditorEditNotice />
            <PptxEditorFontNotice />
            <PptxEditorLoading overlay />
            <PptxEditorOpenFailure />
            <PptxEditorNotesPane />
          </div>
        </div>
        <PptxEditorSlideshow />
      </PptxEditorViewport>
    </PptxEditorRoot>
  </div>
</template>
RequirementWhy
PptxEditorRootOwns the editor instance. It renders no element, so its children sit in your layout.
PptxEditorViewportThe styling scope. It carries .pptx-editor, and dark with a dark color mode. Put every part inside it.
PptxEditorContentThe slide canvas and its context menu.
Editor stylesheetStyles the viewport and the packaged parts. Import it once.
Bounded heightGives the canvas room. Use min-height: 0 on each flex level between the container and the canvas.
Positioned main columnThe find bar, the notices, the loading sheet, and the zoom pill use absolute positions. Give their parent position: relative.

For the CSS of this arrangement, see Workspace layout.

Each part is also a static of PptxEditor. In a template, <PptxEditor.Root> and <PptxEditorRoot> are the same component.

Reach the editor from a parent

Components inside the root call usePptxEditor(). A parent component that renders the root reads the editor through a template ref:

<script setup lang="ts">
import { ref } from 'vue';
import {
  PptxEditorContent,
  PptxEditorRoot,
  PptxEditorViewport,
  type PptxEditorRef,
} from '@pptx-editor.dev/vue';

defineProps<{ bytes: Uint8Array }>();
const editorRef = ref<PptxEditorRef | null>(null);
</script>

<template>
  <button @click="editorRef?.focus()">Back to slide</button>
  <PptxEditorRoot ref="editorRef" :document="bytes">
    <PptxEditorViewport>
      <PptxEditorContent />
    </PptxEditorViewport>
  </PptxEditorRoot>
</template>

For each member, see Use the ref. You can also keep the instance from @ready.

Choose optional components

Mount only the parts that your layout needs. An omitted part renders no interface.

PartPurposeOwner guide
PptxEditorToolbar, PptxEditorRibbon, PptxEditorMenuThe flat toolbar, the tabbed ribbon, and the menu barToolbar, Ribbon, Menus
PptxEditorSlideRail, PptxEditorSlideSorterThe slide thumbnails, and the Slide Sorter viewLayout
PptxEditorNotesPaneThe speaker notes of the current slidePane configuration
PptxEditorSidePanel, PptxEditorSelectionPaneThe Format and Selection panel, and the selection pane aloneLayout
PptxEditorZoomPill, PptxEditorStatusBarA floating zoom control, and a status rowStatus bar
PptxEditorFindBarFind and replace. Without it, Find and Replace stay disabled with a reason.Layout
PptxEditorSlideshowThe slide show. Mount it once inside the viewport.Layout
PptxEditorLoadingThe loading sheet, with the indicator and default slotsLayout
PptxEditorOpenFailureThe notice for a file that does not open, with the actions and message slots and the dismiss eventOpen failure
PptxEditorFontNotice, PptxEditorEditNoticeSubstituted fonts, and the reason the last edit was refusedFonts
PageSetupDialog, ParagraphDialog, and the other dialogsDialogs that the popups registry mounts, or that you mountDialogs

A pane's onOpenChange is the update:open event, so v-model:open controls PptxEditorSlideRail and PptxEditorNotesPane. Each part takes className, and style where React has it. A host class and style also work.

Override a component

A named child replaces the matching control in the preset. hidden removes it, and as-child renders the control as your element:

<PptxEditorToolbar>
  <PptxEditorToolbar.Bold as-child>
    <MyButton variant="ghost">Bold</MyButton>
  </PptxEditorToolbar.Bold>
  <PptxEditorToolbar.Highlight hidden />
</PptxEditorToolbar>

as-child passes the label, the state attributes, and the click handler to the one element in the default slot. An element that is not a button also gets role="button", a tab stop, and Enter and Space. Without as-child, the default slot of a named button part is its icon.

Custom toolbar

Set :preset="false" to render only the parts that you list, in template order:

<PptxEditorToolbar :preset="false" class-name="my-toolbar">
  <PptxEditorToolbar.Undo />
  <PptxEditorToolbar.Redo />
  <PptxEditorToolbar.Separator />
  <PptxEditorToolbar.FontFamily />
  <PptxEditorToolbar.Bold />
  <PptxEditorToolbar.BulletList />
</PptxEditorToolbar>

Each part reads its enabled state, its active state, and its command from the engine. For PptxEditorToolbar.Group, PptxEditorToolbar.Slot, and PptxEditorToolbar.Action, and for every slot identifier, see Toolbar.

Compose the font picker

PptxEditorToolbar.FontFamily is a compound part. FontFamily.Trigger is the button, FontFamily.Content is the list, and FontFamily.Item is one family:

<PptxEditorToolbar>
  <PptxEditorToolbar.FontFamily>
    <PptxEditorToolbar.FontFamily.Trigger class-name="my-font-trigger" />
    <PptxEditorToolbar.FontFamily.Content>
      <PptxEditorToolbar.FontFamily.Item value="Calibri" />
      <PptxEditorToolbar.FontFamily.Item value="Georgia" />
    </PptxEditorToolbar.FontFamily.Content>
  </PptxEditorToolbar.FontFamily>
</PptxEditorToolbar>

To fill the list or build a picker from nothing, use useFontFamily(): value is the current family, groups and options are the families to offer, isCurrent(row) marks the current one, and setValue(family) applies one. See Build the list from useFontFamily.

Control lifetime and focus

PptxEditorRoot creates one instance for its life. This table shows how each prop behaves after a change:

Prop or eventTypeBehavior
documentUint8ArrayA new array opens the new deck in the same instance.
mode'edit' | 'view'Updates in place.
fontsEditorFontsOptionReplaces the fonts in place. The deck, the selection, and the undo history stay.
fontFamiliesreadonly string[]Updates the font picker in place.
localeLocaleCatalogUpdates the strings and repaints the canvas once. Follows the catalog's content, not its identity.
colorMode'light' | 'dark' | 'system'Updates the chrome theme.
popupsPptxEditorPopupsUpdates the dialogs that the root mounts.
@ready, @change, @font-errorEventsReport the instance, every change of editor state, and font failures.

A mousedown that reaches the slide moves the selection. Prevent it on your own chrome, but not on form fields:

<script setup lang="ts">
function keepSelection(event: MouseEvent) {
  const tag = (event.target as HTMLElement | null)?.tagName;
  if (tag === 'INPUT' || tag === 'SELECT' || tag === 'TEXTAREA') return;
  event.preventDefault();
}
</script>

<template>
  <div @mousedown="keepSelection"><!-- Your toolbar --></div>
</template>

Packaged chrome already applies this rule.

Limits

  • Every part must render inside PptxEditorRoot. Outside it, usePptxEditor().value is null.
  • Render one PptxEditorNotesPane in each root. A second one keeps its own state and prints a development warning.
  • In the Slide Sorter view, render PptxEditorSlideSorter in place of the rail, the canvas, and the notes. See Switch between Normal and Slide Sorter.
  • as-child requires exactly one child element. A picker refuses icon and as-child with a development warning.
  • Theme the chrome with --doc-* tokens. The slide canvas always shows the deck's own colors. See Appearance.

See also