← All formats

PPTX

Render PPTX files in the browser with JavaScript.

The examples below render a sample PowerPoint deck (.pptx) in your browser and show the corresponding TypeScript.

Story · Demo

Single viewer with navigation

Hand PptxViewer a canvas and it manages parsing, rendering and the current slide. Step through with the built-in nextSlide() / prevSlide().

sample-1.pptx live · WASM
import { PptxViewer } from '@silurus/ooxml/pptx';

// The built-in viewer tracks the current slide for you.
const viewer = new PptxViewer(canvas, { width: 960, useGoogleFonts: true });
await viewer.load('/sample.pptx');

nextBtn.addEventListener('click', () => viewer.nextSlide());
prevBtn.addEventListener('click', () => viewer.prevSlide());

Story · PptxScrollViewer

Scroll through every slide

Use PptxScrollViewer for a virtualized, ready-made slide stack. For a custom scrolling UI, combine PptxViewer with PptxPresentation and let your application own the container and navigation.

sample-1.pptx live · WASM
import { PptxScrollViewer } from '@silurus/ooxml/pptx';

// The built-in scroll viewer virtualizes a long slide deck for you.
const scroller = document.querySelector('#scroller') as HTMLElement;
const viewer = new PptxScrollViewer(scroller, {
  enableTextSelection: true,
  useGoogleFonts: true,
});

await viewer.load('/sample.pptx');

window.addEventListener('pagehide', (event) => {
  if (event.persisted) return;
  viewer.destroy();
});

Large presentations

Show the opening slides while the deck prepares

Set progressiveLayout: true on PptxViewer, PptxScrollViewer, or PptxPresentation.load(). The opening slide becomes available first while the same sequential preflight continues in the background. The option and lifecycle API deliberately match DOCX progressive layout.

The total is stable

PPTX declares its slide list and uniform dimensions up front. slideCount is final as soon as load() resolves, so a ScrollViewer reserves the full height and its scrollbar does not shrink while slides prepare.

Availability grows

availableSlideCount is the paintable opening prefix. Navigating or scrolling ahead shows a loading state until that slide is ready; already painted slides remain stable.

Subscribe or await

Viewer callbacks receive layoutComplete. Await waitUntilLayoutComplete() before export, full-deck search, or any work that needs every slide prepared.

import { PptxScrollViewer } from '@silurus/ooxml/pptx';

const container = document.querySelector('#presentation') as HTMLElement;
const status = document.querySelector('#status') as HTMLElement;

const viewer = new PptxScrollViewer(container, {
  progressiveLayout: true,
  mode: 'worker',
  onVisibleSlideChange(slideIndex, slideCount, layoutComplete) {
    status.textContent = `Slide ${slideIndex + 1} of ${slideCount}`;
    status.setAttribute('aria-busy', String(!layoutComplete));
  },
});

await viewer.load('/presentation.pptx');

// slideCount and the scrollbar extent are already final here.
// Await only when an operation needs every slide to be paintable.
await viewer.waitUntilLayoutComplete();

Story · ThumbnailGrid

Thumbnail overview

The same engine renders slides at any size. Drop them into a grid at thumbnail width and wire up click handlers for navigation.

sample-1.pptx live · WASM
import { PptxPresentation } from '@silurus/ooxml/pptx';

// Render each slide small, wire up navigation.
const presentation = await PptxPresentation.load('/sample.pptx');

for (let i = 0; i < presentation.slideCount; i++) {
  const thumb = document.createElement('canvas');
  thumb.addEventListener('click', () => open(i));
  grid.appendChild(thumb);
  await presentation.renderSlide(thumb, i, { width: 320 });
}

Story · MasterDetail

Thumbnail rail + large preview

Combine both: a PptxPresentation for the thumbnail rail and a PptxViewer for the detail pane. Click a thumbnail to jump the preview with goToSlide().

sample-1.pptx live · WASM
import { PptxPresentation, PptxViewer } from '@silurus/ooxml/pptx';

// Parse once, then lend the loaded engine to every view that needs it.
const presentation = await PptxPresentation.load('/sample.pptx');

// A large preview on the right borrows the engine and cannot acquire another source.
const viewer = PptxViewer.fromPresentation(detailCanvas, presentation, {
  width: 960,
  enableTextSelection: true,
});
await viewer.goToSlide(0);

// The thumbnail rail on the left renders from that same engine.
for (let i = 0; i < presentation.slideCount; i++) {
  const thumb = document.createElement('canvas');
  thumb.addEventListener('click', () => viewer.goToSlide(i));  // jump the preview
  rail.appendChild(thumb);
  await presentation.renderSlide(thumb, i, { width: 200 });
}

window.addEventListener('pagehide', (event) => {
  if (event.persisted) return;
  viewer.destroy();
  presentation.destroy(); // borrowed engines remain caller-owned
});

Live · Built-in comment UI

Comments in context, rendered by ScrollViewer.

Turn on the built-in read-only UI for slide-side comment cards and authored markers. The Viewer owns positioning, selection, zoom, and scrolling. Comment UI implementation guide →
PPTX ScrollViewer sample-1.pptx

Loading sample-1.pptx…

Comments appear beside the second page.

import { PptxScrollViewer } from '@silurus/ooxml/pptx';

const viewer = new PptxScrollViewer(container, {
  comments: true,
});

await viewer.load(source);