PPTX

Patching

Modify existing .pptx files by replacing placeholders, literal text, or metadata

Patch an existing .pptx template in three ways: replace {{placeholder}} tokens, find-and-replace literal text, or override document metadata.

patchPresentation

Replaces placeholders in an existing .pptx file:

import { patchPresentation, generatePresentation } from "@office-open/pptx";
import { writeFileSync } from "node:fs";

// Create a template with placeholders
const templateBuffer = await generatePresentation({
  title: "Patch Demo",
  slides: [
    {
      children: [
        {
          shape: {
            x: "2.1cm",
            y: "3.2cm",
            width: "19.1cm",
            height: "2.1cm",
            textBody: {
              children: [{ children: [{ text: "Hello {{name}}!" }] }],
            },
          },
        },
      ],
    },
  ],
});

// Patch the template
const result = await patchPresentation({
  outputType: "nodebuffer",
  data: templateBuffer,
  placeholders: {
    name: [{ text: "World", bold: true, size: 24 }],
  },
});

writeFileSync("output.pptx", result);

Placeholders

Placeholder keys are wrapped in delimiters (default {{ and }}) and matched against the slide text. Each value is inline run-level content, reusing the same RunOptions vocabulary as generatePresentation: a single run, an array of runs, or a plain string shorthand.

The original run's formatting properties (font, size, color, bold, etc.) are preserved by default. Any property you set (color, fill, font, hyperlinks, …) is serialized via the same descriptor as generatePresentation.

placeholders: {
  title: [
    { text: "Hello ", bold: true },
    { text: "World", fill: { type: "solid", color: "FF0000" } },
  ],
  link: { text: "Click", hyperlink: { url: "https://example.com" } },
  plain: "just text",
}

Find and Replace

Replace literal text without any delimiters — the keys are matched verbatim. Useful for rebranding or updating fixed wording in a template:

const result = await patchPresentation({
  outputType: "nodebuffer",
  data: templateBuffer,
  findReplace: {
    "Acme Corp": [{ text: "Globex", bold: true }],
    Draft: "Final",
  },
});

Core Properties

Override document metadata (docProps/core.xml). Values are merged over the existing core properties — supply only the fields you want to change:

const result = await patchPresentation({
  outputType: "nodebuffer",
  data: templateBuffer,
  coreProperties: { title: "Quarterly Review", creator: "Jane Doe" },
});

Slides

Append new slides or replace existing ones by index (0-based, in sldIdLst order). Each entry reuses the full SlideOptions vocabulary from generatePresentation:

const result = await patchPresentation({
  outputType: "nodebuffer",
  data: templateBuffer,
  slides: {
    append: [
      {
        children: [
          {
            shape: {
              x: "0.0cm",
              y: "0.0cm",
              width: "15.9cm",
              height: "10.6cm",
              textBody: { text: "New slide" },
            },
          },
        ],
      },
    ],
    replace: {
      0: {
        children: [
          {
            shape: {
              x: "0.0cm",
              y: "0.0cm",
              width: "15.9cm",
              height: "10.6cm",
              textBody: { text: "Replaced" },
            },
          },
        ],
      },
    },
  },
});

Appended slides are serialized through the same slide stringifier as generation and wired into sldIdLst, the presentation relationships, and [Content_Types].xml. Each appended slide inherits the template's first slide layout — it cannot reference layouts, masters, or media that the template does not already contain. Replaced slides keep their existing identity (sldId, rId, and relationships).

Comments

Append comments to existing slides, keyed by 0-based slide index (in sldIdLst order). Each comment reuses the SlideCommentOptions vocabulary from generatePresentation (see ). Authors are merged into commentAuthors.xml (deduped by name, ids continued) and per-slide comments are merged into ppt/comments/commentN.xml:

const result = await patchPresentation({
  outputType: "nodebuffer",
  data: templateBuffer,
  comments: {
    0: [{ author: "Alice", text: "Review the opening", x: "2.6cm", y: "4.0cm" }],
    1: [{ author: "Bob", text: "Add a chart here", x: "2.6cm", y: "4.0cm" }],
  },
});

Existing authors and comments are preserved — new entries are appended and re-serialized.

Custom Delimiters

Default delimiters are {{ and }}. Change them with placeholderDelimiters:

await patchPresentation({
  outputType: "nodebuffer",
  data: templateBuffer,
  placeholders: { name: [{ text: "John" }] },
  placeholderDelimiters: { start: "<<", end: ">>" },
});

Options

OptionTypeDefaultDescription
outputTypestringOutput format (see Export page)
dataBuffer | Uint8Array | ...Input .pptx file data
placeholdersRecord<string, RunOptions | RunOptions[] | string>Delimiter-wrapped placeholder name → run content
findReplaceRecord<string, RunOptions | RunOptions[] | string>Literal find string → run content (no delimiters)
corePropertiesPartial<CorePropertiesOptions>Core metadata override, merged over existing values
slides{ append?, replace? }Append slides or replace slides by 0-based index
commentsRecord<number, SlideCommentOptions[]>Append comments to slides by 0-based index (merged with existing)
keepOriginalStylesbooleantruePreserve original run formatting properties
placeholderDelimiters{ start: string, end: string}{ start: "{{", end: "}}" }Custom placeholder delimiters

Tips

  • Placeholders span across split runs in PowerPoint — the library handles this automatically.
  • placeholders and findReplace share one engine; combine both in a single call.
  • Scanning covers slides, slide masters, slide layouts, and notes slides — replacing text in a master/layout propagates to every dependent slide.
  • Hyperlinks introduced by patch runs are registered into each slide's relationship part automatically.
Copyright © 2026