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.
PPTX
The examples below render a sample PowerPoint deck (.pptx) in your browser and show
the corresponding TypeScript.
Story · Demo
Hand PptxViewer a canvas and it manages parsing, rendering and the current slide. Step through with the built-in nextSlide() / prevSlide().
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
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.
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
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.
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.
availableSlideCount is the paintable opening prefix. Navigating or
scrolling ahead shows a loading state until that slide is ready; already painted
slides remain stable.
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
The same engine renders slides at any size. Drop them into a grid at thumbnail width and wire up click handlers for navigation.
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
Combine both: a PptxPresentation for the thumbnail rail and a PptxViewer for the detail pane. Click a thumbnail to jump the preview with goToSlide().
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 →Loading sample-1.pptx…
Comments appear beside the second page.