
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
pptx-json-parser
Advanced tools
Parse PPTX files to structured JSON data for rendering in any framework
Parse PPTX files to structured JSON data for rendering in any framework
A framework-agnostic PPTX parser that converts PowerPoint presentations into structured JSON data. Perfect for building custom presentation viewers in React, Vue, Angular, or vanilla JavaScript.
npm install pptx-json-parser
Or using pnpm:
pnpm add pptx-json-parser
import { parsePPTXToSlides } from 'pptx-json-parser';
// Fetch PPTX file
const response = await fetch('presentation.pptx');
const arrayBuffer = await response.arrayBuffer();
// Parse to structured data
const slides = await parsePPTXToSlides(arrayBuffer, {
containerWidth: 800, // Optional: target width (default: 800)
themeColors: ['#1890ff', '#52c41a'], // Optional: custom theme colors
});
console.log(slides);
// Output: Array of Slide objects with structured element data
interface Slide {
id: string;
elements: BaseElement[];
background: SlideBackground;
remark: string;
}
PPTTextElement) - Rich text with formattingPPTImageElement) - Images with clipping and effectsPPTShapeElement) - Vector shapes with fills and gradientsPPTTableElement) - Tables with cell stylingPPTChartElement) - Charts (bar, line, pie, etc.)PPTVideoElement) - Video elementsPPTAudioElement) - Audio elementsPPTLineElement) - Lines and connectorsimport { parsePPTXToSlides, Slide, BaseElement } from 'pptx-json-parser';
import { useEffect, useState } from 'react';
function PPTViewer({ url }: { url: string }) {
const [slides, setSlides] = useState<Slide[]>([]);
useEffect(() => {
fetch(url)
.then((r) => r.arrayBuffer())
.then((buffer) => parsePPTXToSlides(buffer))
.then(setSlides);
}, [url]);
const renderBackground = (background: Slide['background']) => {
if (background.type === 'solid') {
return { backgroundColor: background.color };
} else if (background.type === 'image') {
return {
backgroundImage: `url(${background.image?.src})`,
backgroundSize: background.image?.size || 'cover',
};
} else if (background.type === 'gradient') {
const { gradient } = background;
const colors = gradient?.colors.map((c) => `${c.color} ${c.pos}%`).join(', ');
return {
background:
gradient?.type === 'linear'
? `linear-gradient(${gradient.rotate}deg, ${colors})`
: `radial-gradient(${colors})`,
};
}
};
const renderElement = (element: BaseElement) => {
const baseStyle = {
position: 'absolute',
left: element.left,
top: element.top,
width: element.width,
height: element.height,
transform: element.rotate ? `rotate(${element.rotate}deg)` : undefined,
};
switch (element.type) {
case 'text':
const textEl = element as PPTTextElement;
return (
<div
style={baseStyle}
dangerouslySetInnerHTML={{ __html: textEl.content }}
/>
);
case 'image':
const imageEl = element as PPTImageElement;
return (
<img
src={imageEl.src}
style={{
...baseStyle,
objectFit: imageEl.objectFit,
}}
alt={imageEl.alt}
/>
);
// Add more element types as needed...
default:
return null;
}
};
return (
<div className="ppt-container">
{slides.map((slide, index) => (
<div
key={slide.id}
className="slide"
style={{
position: 'relative',
width: 800,
height: 450,
...renderBackground(slide.background),
}}
>
<div className="slide-number">Slide {index + 1}</div>
{slide.elements.map((element) => (
<div key={element.id}>{renderElement(element)}</div>
))}
</div>
))}
</div>
);
}
<template>
<div class="ppt-container">
<div
v-for="(slide, index) in slides"
:key="slide.id"
class="slide"
:style="getBackgroundStyle(slide.background)"
>
<div class="slide-number">Slide {{ index + 1 }}</div>
<component
v-for="element in slide.elements"
:key="element.id"
:is="getElementComponent(element.type)"
:element="element"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { parsePPTXToSlides, type Slide } from 'pptx-json-parser';
const props = defineProps<{ url: string }>();
const slides = ref<Slide[]>([]);
onMounted(async () => {
const response = await fetch(props.url);
const buffer = await response.arrayBuffer();
slides.value = await parsePPTXToSlides(buffer);
});
const getBackgroundStyle = (background: Slide['background']) => {
// Implementation similar to React example
};
</script>
import { parsePPTXToSlides } from 'pptx-json-parser';
async function loadPresentation(url) {
const response = await fetch(url);
const buffer = await response.arrayBuffer();
const slides = await parsePPTXToSlides(buffer);
const container = document.getElementById('ppt-container');
slides.forEach((slide, index) => {
const slideEl = document.createElement('div');
slideEl.className = 'slide';
slideEl.style.position = 'relative';
slideEl.style.width = '800px';
slideEl.style.height = '450px';
// Render background
if (slide.background.type === 'solid') {
slideEl.style.backgroundColor = slide.background.color;
}
// Render elements
slide.elements.forEach((element) => {
const elementEl = document.createElement('div');
elementEl.style.position = 'absolute';
elementEl.style.left = element.left + 'px';
elementEl.style.top = element.top + 'px';
elementEl.style.width = element.width + 'px';
elementEl.style.height = element.height + 'px';
if (element.type === 'text') {
elementEl.innerHTML = element.content;
} else if (element.type === 'image') {
const img = document.createElement('img');
img.src = element.src;
elementEl.appendChild(img);
}
slideEl.appendChild(elementEl);
});
container.appendChild(slideEl);
});
}
loadPresentation('presentation.pptx');
parsePPTXToSlides(arrayBuffer, options?)Parses a PPTX file ArrayBuffer into structured slide data.
Parameters:
arrayBuffer (ArrayBuffer): The PPTX file dataoptions (ParseOptions, optional):
containerWidth (number): Target slide width (default: 800)themeColors (string[]): Custom theme colorsReturns: Promise<Slide[]>
import type {
Slide,
BaseElement,
PPTTextElement,
PPTImageElement,
PPTShapeElement,
PPTTableElement,
PPTChartElement,
// ... and many more
} from 'pptx-json-parser';
import {
generateId,
convertFontSizePtToPx,
getSvgPathRange,
calculateRotatedPosition,
flipGroupElements,
} from 'pptx-json-parser';
const slides = await parsePPTXToSlides(arrayBuffer, {
themeColors: [
'#FF6B6B',
'#4ECDC4',
'#45B7D1',
'#FFA07A',
'#98D8C8',
'#F7DC6F',
],
});
const containerWidth = window.innerWidth;
const slides = await parsePPTXToSlides(arrayBuffer, { containerWidth });
Contributions are welcome! Please feel free to submit a Pull Request.
By separating parsing from rendering, you can:
Implement virtual scrolling/pagination in your renderer to only render visible slides.
Yes! The parser works in Node.js environments. Just note that some features like table parsing may require DOM APIs (you can use jsdom).
Built with using pptxtojson
FAQs
Parse PPTX files to structured JSON data for rendering in any framework
We found that pptx-json-parser demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.