Skip to content

What is pptx-viewer?

pptx-viewer is a TypeScript monorepo for parsing, editing, rendering, and converting Microsoft PowerPoint (.pptx) files - in the browser and in Node.js. It works entirely in-memory on the OpenXML ZIP archive with no native dependencies.

pptx-viewer covers the full round-trip: load an existing deck, mutate its structured data model, render it, and save it back to a valid .pptx file. The same core engine powers components for React, Vue 3, Angular, and Svelte 5, plus a vanilla JavaScript build for projects without a framework.

What it does

The SDK provides nine core capabilities:

  1. Parse .pptx files from a raw ArrayBuffer into a structured PptxData model.
  2. Create presentations from scratch with a fluent builder API.
  3. Render slides as interactive React, Vue, Angular, Svelte, or vanilla JS components.
  4. Edit presentations programmatically or via the built-in WYSIWYG editor.
  5. Save changes back to a valid .pptx file (round-trip safe).
  6. Convert presentations to Markdown with optional media extraction.
  7. Export slides as images (PNG/JPEG), SVG, PDF, GIF, or video.
  8. Collaborate in real time via Yjs CRDT with presence tracking.
  9. Encrypt/Decrypt password-protected PPTX files (AES-128/256).

The engine handles the full OpenXML specification including 16 element types, 187+ preset shapes, 23 chart types, SmartArt, 3D models, animations, transitions (including morph), themes, slide masters, embedded media, EMF/WMF metafiles, OLE objects, digital ink, digital signatures, encryption, VBA macro preservation, and OOXML Strict conformance.

Who is it for

  • Product teams embedding a document viewer: show user-uploaded decks inside a web app without shipping files to a conversion service.
  • Teams building an editor: the bindings include a full WYSIWYG editing surface (ribbon, inspector, undo/redo, collaboration) you can enable per feature.
  • Backend and automation work: the core package is framework-agnostic and runs in Node.js, so you can generate, inspect, diff, or convert decks in scripts, servers, and CI.
  • AI and agent pipelines: pptx-viewer-mcp exposes the engine as MCP tool calls, and the Markdown converter turns decks into LLM-friendly text.

Rendering model

pptx-viewer does not rasterize slides, server-side or onto a <canvas>. Slides render as HTML, CSS, and SVG in the DOM:

  • Text is real HTML text: selectable, searchable, translatable, and readable by screen readers.
  • Shapes and connectors are SVG with computed clip paths from the geometry engine.
  • Tables are HTML <table> elements; charts are inline SVG built from the parsed chart data.
  • Zooming is a CSS transform, so slides stay sharp at any scale on any display density.
  • Because every element is a DOM node, the editor gets selection, drag handles, inline text editing, and accessibility for free.

Rasterization only happens when you ask for it: raster export (PNG/JPEG/PDF/GIF/video) draws the DOM through html2canvas.

Tradeoffs

CSS cannot express every PowerPoint effect pixel-perfectly (for example some blend modes and 3D rotations are approximated). See Limitations for the full list.

The packages

The monorepo ships eight published packages.

Packagenpm namePurpose
Corepptx-viewer-coreParse, create, edit, serialize, and convert PPTX files. Framework-agnostic.
Reactpptx-react-viewerReact viewer, editor, and presenter with toolbar, inspector, collaboration, and export.
Vue 3pptx-vue-viewerVue 3 viewer/editor built on the same engine, with the same feature set.
Angularpptx-angular-viewerAngular viewer/editor built on the same engine, with the same feature set.
Vanilla JSpptx-vanilla-viewerZero-framework binding built on the same engine: plain DOM, one factory function, no framework dependency.
Sveltepptx-svelte-viewerSvelte 5 component built on the same engine, with the same feature set.
Tools / MCPpptx-viewer-mcp50+ PPTX tool functions, an MCP server for AI agents, and the Y.Doc collaboration codec.
Installer@christophervr/pptx-viewerInteractive CLI that scaffolds the right viewer package into your project.

How the pieces fit

All five UI binding packages build on a shared rendering layer, which in turn builds on Core:

pptx-react-viewer   ┐
pptx-vue-viewer     │
pptx-angular-viewer ├── pptx-viewer-shared ── pptx-viewer-core
pptx-vanilla-viewer │                               ├── emf-converter
pptx-svelte-viewer  ┘                               └── mtx-decompressor
  • pptx-viewer-core owns everything about the file format: the load and save pipelines, the typed data model, theme resolution, the geometry engine, encryption, and the Markdown/SVG converters. It has no UI and runs anywhere JavaScript runs.
  • pptx-viewer-shared holds the framework-agnostic viewer logic: style and gradient resolution, chart and axis maths, connector routing, animation and morph engines, export preparation. It is an internal package: private, never published to npm, and bundled into each binding at build time. You never install it directly.
  • The bindings are thin view layers. Each translates the same shared render data into its framework's idiom (JSX, SFC templates, Angular templates, Svelte runes, or plain DOM), which is why the five bindings render identically and stay at feature parity.
  • emf-converter (EMF/WMF metafile to PNG) and mtx-decompressor (MicroType Express embedded fonts) are standalone npm dependencies of Core.
  • pptx-viewer-mcp builds on pptx-viewer-core to expose tool-call and collaboration surfaces for AI agents.

Minimal examples

ts
import { PptxHandler } from 'pptx-viewer-core';

const handler = new PptxHandler();
const data = await handler.load(arrayBuffer);

// data.slides is a typed, mutable model
data.slides[0].elements.filter((el) => el.type === 'text').forEach((el) => console.log(el.text));

const bytes = await handler.save(data.slides); // => Uint8Array (.pptx)
ts
import { PptxHandler } from 'pptx-viewer-core';

const { handler, data, createSlide } = await PptxHandler.create({
	title: 'Q4 Report',
	theme: { colors: { accent1: '#FF6B6B' } },
});

data.slides.push(createSlide('Blank').addText('Hello', { fontSize: 36 }).build());

const bytes = await handler.save(data.slides);

Next steps

Released under the Apache-2.0 License.