πŸ“Š node-pptx-templater v1.0.0

Introduction

A low-level, high-performance PowerPoint OpenXML templating engine for Node.js. It generates and edits PPTX files directly through structured XML manipulation, avoiding fragile regex replacements and eliminating standard "Repair Mode" issues.

⚑ Why node-pptx-templater? It runs on pure Javascript/ESM with zero native PPTX generator dependencies, making it ultra-lightweight and ideal for high-throughput server environments or serverless runtimes.

Features At A Glance

πŸ“¦ Structured XML Parsing

Every file modification uses a fast, reliable DOM-like abstraction instead of raw text replacement.

πŸ”„ In-Memory Manifests

Guards packaging integrity via atomic serialization of relationships and content types.

πŸ“‹ Deep Slide Imports

Clones slides across templates, preserving all associated layouts, charts, links, and styling.

πŸ“Š Accurate Chart Updates

Synchronizes chart XML and underlying data caches directly inside embedded Excel sheets.

Installation

Install the library via npm. Make sure you meet the requirement of having Node.js version 18.0.0 or higher.

npm install node-pptx-templater

System Requirements

  • Node.js: >= 18.0.0
  • Module system: ES Modules ("type": "module" in package.json)

Quick Start

Get up and running in under 60 seconds with this simple template rendering example.

import { PPTXTemplater } from 'node-pptx-templater';

// Load the source template
const ppt = await PPTXTemplater.load('template.pptx');

// Select slide 1 and execute operations
ppt.useSlide(1);

// Safely replace text placeholders
ppt.replaceText({
  '{{title}}': 'Quarterly Earnings Report',
  '{{date}}': 'May 2026'
});

// Update an interactive bar chart
ppt.updateChart('sales-chart', {
  categories: ['Q1', 'Q2', 'Q3', 'Q4'],
  series: [
    { name: 'Revenue ($M)', values: [120, 145, 170, 210] }
  ]
});

// Save non-corrupted PPTX to disk
await ppt.saveToFile('./output/annual_report.pptx');

Slide Import Engine

The Slide Import engine allows robust deep copying of individual slides from one template into another.

Unlike basic copy implementations, importSlideFrom performs an exhaustive search and deep-copy of all associated relationships, slide layouts, embedded media, and chart workbooks, remapping them into the new presentation's namespace.

Example: Merging Slide Decks

import { PPTXTemplater } from 'node-pptx-templater';

const master = await PPTXTemplater.load('master_template.pptx');
const source = await PPTXTemplater.load('department_results.pptx');

// Deep-copy slide 2 from department_results into master template
await master.importSlideFrom(source, 2);

// Save the combined deck
await master.saveToFile('merged_presentation.pptx');
Pro-tip: When importing a slide, media deduplication automatically checks if the image is already present in the destination deck, preventing asset bloating!

ContentTypesManager

Every single file inside an OpenXML ZIP package must have its type registered inside the centralized manifest [Content_Types].xml.

Our centralized ContentTypesManager replaces standard fragile string replacements with a parsed in-memory node-tree representation of the manifest. Changes are flushed only during the final package writing step to completely eliminate race conditions.

API Reference

// Inside PPTXTemplater lifecycle:
const contentTypes = ppt.contentTypesManager;

// Override registration for new slide XML
contentTypes.addOverride('/ppt/slides/slide3.xml', 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml');

// Default MIME registration
contentTypes.addDefault('webp', 'image/webp');

RelationshipManager

Relationships define how slides link to layouts, masters, charts, and media assets. Standard regex tools corrupt relationship chains if IDs are not fully unique.

The RelationshipManager provides bulletproof remapping and creation of relative relationship paths inside standard .rels files.

Usage Example

const rels = ppt.relationshipManager;

// Add a safe relationship to slides/slide1.xml
const rId = rels.addRelationship(
  'ppt/slides/slide1.xml',
  'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
  '../media/image10.png'
);
// Returns unique ID (e.g. 'rId5')

PPTXTemplater

The main class exposed by the library to load, select, modify, and save presentation templates.

Properties & Getters

Property Type Description
slideCount number Returns the total count of active slides in the loaded deck.
relationshipManager RelationshipManager Access direct relationship operations.
contentTypesManager ContentTypesManager Access manifest definitions.

Main Methods

Method Arguments Returns Description
useSlide (slideNumberOrTag) PPTXTemplater Restricts text, table, and chart updates to only target specific slides.
replaceText (replacements) PPTXTemplater Performs structured substitution on text, handles run fragmentation cleanly.
saveToFile (filePath) Promise<void> Saves all dirty cached XML parts and updates metadata counts before writing.

Chart Engine

PowerPoint charts are structured via complex pairings of a Chart XML part and an embedded Excel Worksheet binary containing matching row/column data cells.

Our Chart Engine automatically updates the underlying series formulas, Category axis values, and regenerates both strCache and numCache so Google Slides and LibreOffice display charts instantly without requiring user-refresh triggers.

Updating Chart Data

ppt.updateChart('revenue-chart', {
  categories: ['Q1', 'Q2', 'Q3', 'Q4'],
  series: [
    { name: 'Target', values: [100, 120, 140, 160] },
    { name: 'Actual', values: [105, 118, 145, 172] }
  ]
});

Table Engine

Dynamically scale template tables. The Table Engine lets you replace placeholder rows while fully preserving the styles, fonts, backgrounds, and cell heights of the original template row.

Example Table Feeding

ppt.updateTable('team-roster', [
          ['Name', 'Title', 'Location'],
          ['Elena', 'Lead Designer', 'Milan'],
          ['Keigo', 'Research Engineer', 'Tokyo'],
          ['Tariq', 'Product Manager', 'Cairo']
        ]);

OpenXML Architecture

An inside look at how files are packaged and managed within the PPTX OpenXML structure.

            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚                 PPTXTemplater                 β”‚
            β”‚                  (Public API)                 β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚                              β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚   SlideManager  β”‚            β”‚   ChartManager  β”‚
            β”‚  (discovery &   β”‚            β”‚   (Excel & cacheβ”‚
            β”‚   slide CRUD)   β”‚            β”‚    synchronizer)β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚                              β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚                 XMLParser                     β”‚
            β”‚         (fast-xml-parser parsing tree)         β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚                              β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚ ContentTypesMgr β”‚            β”‚ RelationshipMgr β”‚
            β”‚ (Overrides list)β”‚            β”‚ (.rels mapper)  β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                     β”‚                              β”‚
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚                 ZipManager                    β”‚
            β”‚            (JSZip raw serialization)          β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
          

Troubleshooting

My presentation shows "PowerPoint found a problem with content..."

This is commonly caused by out-of-sync slide count metadata in docProps/app.xml or an override registration missing from [Content_Types].xml.

The Solution: Always make sure to use ppt.saveToFile() or ppt.toBuffer(), which automatically run metadata-synchronization passes and flush all manifest changes.

My placeholders aren't replacing!

PowerPoint split-runs break placeholders like {{placeholder}} into multiple separate <a:t> tags. Enable logging output to identify where fragmentation occurs:

PPTX_LOG_LEVEL=debug node script.js