# React PPTX Viewer: Slides, Notes and Presenter Mode

> Build a React PPTX viewer that draws real slides in the browser, with thumbnails, search, speaker notes and a presenter mode, and learn when a PDF works better.

- Author: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Published: Nov 5, 2026
- Category: [Component guides](https://wingo-ui.com/blog/category/components)
- Reading time: 9 min
- Canonical: https://wingo-ui.com/blog/react-pptx-viewer

## TL;DR

A React PPTX viewer unzips the .pptx in the browser, rebuilds each slide from its layout, master and theme, and draws it as HTML and SVG, so the file never goes to a conversion server and the text stays selectable. The PowerPoint Viewer in Wingo UI Pro does this and adds slide thumbnails, zoom, search across slides and speaker notes, and a fullscreen presenter. Convert to PDF instead when every reader must see identical pages, when the deck relies on animations or video, or when you have to open old .ppt files.

Someone uploads a sales deck and your app has to show it: the real slides with their colors and charts, a strip of thumbnails, and ideally the speaker notes. A download link makes them leave the page, and a PDF export loses the notes and the editable file. A React PPTX viewer has to rebuild each slide from the XML inside the .pptx, which means layouts, masters, theme colors, fonts, tables and charts. This guide covers the options and then builds one with the [PowerPoint Viewer](https://wingo-ui.com/components/pptx-viewer) from Wingo UI, the library we make, so we are not neutral; facts about other projects link to their sources.

## What are the ways to show a PowerPoint file in React?

There are four realistic routes: Microsoft's online viewer in an iframe, an open source parser that runs in the browser, a commercial document SDK, or a conversion to PDF before anyone views it. They differ mostly in where the file goes. Facts below come from each project's own page, checked November 5, 2026.

| Approach | Where the file goes | What you get | Catch |
|---|---|---|---|
| Microsoft's Office viewer in an iframe | Microsoft's servers | Microsoft's own rendering | [react-doc-viewer](https://github.com/cyntler/react-doc-viewer) uses this service for .ppt and .pptx and supports public file URLs only |
| [@extend-ai/react-pptx](https://github.com/extend-hq/react-pptx) (MIT) | Stays in the browser | Rust and WebAssembly parser, HTML and SVG slides, .pptx and legacy .ppt | Its README puts animation timelines, macros, media playback and password decryption outside v1 |
| [PptxViewJS](https://github.com/gptsci/pptxviewjs) (MIT) | Stays in the browser | Slides drawn on a canvas, charts through Chart.js | Canvas text is not selectable; a young project with a single commit at the time of writing |
| Commercial SDKs such as [Nutrient](https://www.nutrient.io/blog/how-to-build-a-react-powerpoint-viewer/) | Stays in the browser (WebAssembly) | Converts the deck to PDF on the device, then shows the PDF | Production needs a license key that includes Office viewing; what people see is a PDF of the deck |
| Convert to PDF on your server | Your server, once | Identical pages everywhere | Read-only, no speaker notes, no slide data |

For react doc viewer PPTX support, the first row is the whole story: `@cyntler/react-doc-viewer` passes .ppt and .pptx files to Microsoft's online viewer in an iframe, which needs a public URL, so a private deck behind your login cannot use it. For private files the in-browser parsers are the real choice. Extend also publishes a shadcn-style [PPTX viewer component](https://ui.extend.ai/docs/components/pptx-viewer) on top of its package, with virtualized thumbnails, zoom, upload and download; its docs page does not mention speaker notes or a presenter mode.

The Wingo UI PowerPoint Viewer takes the same in-browser route with its own parser. It unzips the file with fflate, a small zip library that loads with the first presentation instead of with your route bundle, and inflates large parts in a worker. It then reads the slide, layout, master and theme parts, and draws shapes, text, pictures, tables and charts as HTML and SVG. Because text stays text, you can select it, search it and read it with a screen reader. That is the main difference from a canvas-based PPTX viewer JavaScript library such as PptxViewJS.

## How do I add a React PPTX viewer to a Next.js app?

Install the component with the CLI. It brings fflate, lucide-react and the Wingo UI parts it uses (button, dropdown menu, popover, tooltip):

```bash
npx wingo-ui@latest add pptx-viewer
```

The component is a client component, so a server page can render it directly. `src` accepts a same-origin URL, a CORS-enabled URL or a `blob:` URL:

```tsx
// app/decks/[id]/page.tsx
import { PptxViewer } from "@/components/ui/pptx-viewer"

export default function DeckPage() {
  return (
    <PptxViewer
      src="/files/q3-business-review.pptx"
      fileName="Q3 2026 business review.pptx"
      height="80dvh"
    />
  )
}
```

That one element is a complete React PPTX preview: a toolbar with slide navigation, zoom and search, a sidebar of thumbnails (hidden slides dimmed), and a column of slides you scroll through. Only the slides near the view are drawn, so long decks stay light while you scroll. `defaultZoom="automatic"` fits the slide width up to 100%, and `maxFileSize` (100 MB by default) refuses bigger files before parsing and offers the download instead.

Try it with the sample quarterly review below. Search for "Midwest": hits on the slides and in the speaker notes both count, and the counter steps through them with Enter.

> Live demo (PowerPoint Viewer): Scroll through the sample deck, pick a thumbnail, then press Ctrl or Cmd+F and search for Midwest to see hits on the slides and in the notes. Try it at [PowerPoint Viewer](https://wingo-ui.com/components/pptx-viewer) and install it with `npx wingo-ui@latest add pptx-viewer`.

When people pick a deck on their own device, you do not need an upload. The ⋯ menu opens another .pptx, a file dropped onto the viewer opens too, and `onPresentationUpload` hands you the `File` if you want to store it. On read-only screens, turn that off with `showUpload={false}`.

## How do speaker notes and presenter mode work?

Speaker notes live in their own parts of the .pptx, one per slide, and the viewer reads them as plain text. `defaultNotesVisible` opens the notes of the current slide under it; the Speaker notes switch in the toolbar toggles them, and it is disabled when the file has no notes. Search covers the notes too, and a hit in the notes opens them.

The Present button goes fullscreen, one slide at a time, with hidden slides left out. Click, Space, the arrow keys or Page Up and Page Down advance; Home and End jump; Escape leaves. On a phone you swipe left or right, and phones without the Fullscreen API get a fixed overlay instead.

This sample opens on slide 3 with its notes visible and one slide at a time, the way a presenter rehearses:

> Live demo (PowerPoint Viewer): The deck opens on slide 3 in single slide view with the speaker notes under it; use the arrows to step through, then press Present to go fullscreen. Try it at [PowerPoint Viewer](https://wingo-ui.com/components/pptx-viewer) and install it with `npx wingo-ui@latest add pptx-viewer`.

### Build a slide list and a Present button

`onPresentationLoadSuccess` hands you every slide's number, title, hidden flag, notes and layout name, plus the slide size and the document properties. Combine it with the ref and `onSlideChange` to build your own contents list next to the viewer:

```tsx
"use client"

import { useRef, useState } from "react"
import { Button } from "@/components/ui/button"
import { PptxViewer, type PptxViewerHandle, type PptxViewerSlideInfo } from "@/components/ui/pptx-viewer"

export function DeckReview({ src }: { src: string }) {
  const viewer = useRef<PptxViewerHandle>(null)
  const [slides, setSlides] = useState<PptxViewerSlideInfo[]>([])
  const [current, setCurrent] = useState(1)

  return (
    <div className="flex flex-col gap-4 md:flex-row">
      <nav aria-label="Slides" className="flex flex-col gap-1 md:w-60">
        {slides.map((slide) => (
          <button
            key={slide.number}
            type="button"
            aria-current={slide.number === current ? "true" : undefined}
            onClick={() => viewer.current?.goToSlide(slide.number, { behavior: "smooth" })}
            className="h-11 truncate rounded-[10px] px-3 text-start text-sm hover:bg-foreground/5 aria-[current]:bg-foreground/10"
          >
            {slide.number}. {slide.title}
          </button>
        ))}
        <Button onClick={() => viewer.current?.enterPresentation(current)}>Present from slide {current}</Button>
      </nav>
      <PptxViewer
        ref={viewer}
        src={src}
        height={560}
        defaultSidebarOpen={false}
        className="min-w-0 flex-1"
        onSlideChange={setCurrent}
        onPresentationLoadSuccess={(deck) => setSlides(deck.slides)}
      />
    </div>
  )
}
```

The same slide data is useful outside the viewer: store the titles and notes next to the file, and your own search or an AI assistant can find a deck by what the presenter says on slide 7. For approval flows, `toolbarActions` puts your buttons (Share, Approve deck) at the end of the toolbar, and `renderSlideOverlay` draws on top of each slide with its size and scale at the current zoom, so a review pin placed in percent stays on its spot while people zoom.

## How does a React PowerPoint viewer behave on a phone?

It adapts to the width it is given, because a React PowerPoint viewer lands in narrow side panes as often as on phones. The PowerPoint Viewer measures its own box with a ResizeObserver and ignores the window size. Below 720px (880px when you pass `toolbarActions`) the Single slide and Speaker notes switches, Present and Download move into the ⋯ menu. Below 520px the thumbnail sidebar starts closed and slides over the slides when opened, and below 440px the zoom steps fold into the menu too. Menus open as bottom sheets on phones, two fingers pinch to zoom around the point between them, and Ctrl or ⌘ plus scroll does the same with a mouse. Slides keep their own colors in dark mode, because a deck is a designed artifact and inverting it would misrepresent it.

On the keyboard, ← → and Page Up / Page Down change slides, Home and End jump to the ends, and Ctrl+F or ⌘F opens the viewer's search while focus is inside it. Outside the viewer, the browser's own find keeps working.

## What does not render, and when is a PDF the better choice?

Animations, media, a few picture formats, compressed embedded fonts and old .ppt files do not render, and a PDF is the better choice when those matter or when every reader must see identical pages. In detail, with the PowerPoint Viewer:

- **Animations and transitions** are not played. Each slide shows in its final state with every shape visible.
- **Video, audio and embedded objects** (an embedded workbook, for example) show a labeled placeholder, with the object's preview picture when the file has one.
- **EMF, WMF and TIFF pictures** cannot be drawn by a browser and show a labeled placeholder.
- **Fonts** embedded by PowerPoint or Google Slides are used; compressed embedded fonts are not decoded. A missing font falls back to a close one (Carlito for Calibri when installed), so a line can wrap differently.
- **Old .ppt and password-protected files** show an error that asks for a .pptx.

Charts render from the values PowerPoint saves inside the file (bar, line, area and pie), and SmartArt renders from the drawn copy PowerPoint stores next to it, so both match what the author last saw.

Export to PDF when those limits matter: a signed proposal where slide 9 must look the same for everyone, an archive, a deck that depends on animation builds, or a library of old .ppt files. LibreOffice converts on the server from the command line ([start parameters](https://help.libreoffice.org/latest/en-US/text/shared/guide/start_parameters.html)):

```bash
soffice --headless --convert-to pdf --outdir ./converted deck.pptx
```

Then show the result in the [PDF Viewer](https://wingo-ui.com/components/pdf-viewer), which has the same kind of toolbar, thumbnails and search plus highlights with notes; our [React PDF viewer guide](https://wingo-ui.com/blog/react-pdf-viewer) walks through it. Many apps keep both: the .pptx in the PowerPoint Viewer while the deck is in review, the PDF once it is final. Word files follow the same logic with the [DOCX Viewer](https://wingo-ui.com/components/docx-viewer) (see the [React DOCX viewer guide](https://wingo-ui.com/blog/react-docx-viewer)), and spreadsheets with the [Excel Viewer](https://wingo-ui.com/components/excel-viewer).

## What breaks when you load decks from other origins or uploads?

Cross-origin URLs without CORS headers, decks too heavy for a phone and unchecked uploads are what break in production. Settle all three before launch:

- **CORS.** A deck on another origin, such as an S3 bucket, needs `Access-Control-Allow-Origin` for your site, or fetch it on your server and serve it from your domain. For a file in memory, `URL.createObjectURL(file)` gives you a `blob:` URL to pass as `src`; revoke it when the viewer unmounts.
- **Size.** Decks with video can be hundreds of megabytes, and every byte is downloaded and unzipped on the device. Keep `maxFileSize` at a limit your users' phones can handle; video and audio parts stay compressed because they are never drawn.
- **Uploads.** If people send you decks first, validate the type and size before you store them. The [React file upload guide](https://wingo-ui.com/blog/react-file-upload) covers that flow, and the [File Upload](https://wingo-ui.com/components/file-upload) component handles picking and progress.

## What is the next step?

Install the viewer with `npx wingo-ui@latest add pptx-viewer` and point `src` at one of your own decks, ideally one with a chart, a table and speaker notes, since that is where renderers differ. The PowerPoint Viewer, DOCX Viewer and PDF Viewer are part of Wingo UI Pro, from $8 a month or $150 once for lifetime access (as of November 2026); the [Wingo UI pricing page](https://wingo-ui.com/pricing) lists every plan. For more guides like this one, browse the [component guides](https://wingo-ui.com/blog/category/components) or start with the [React form components guide](https://wingo-ui.com/blog/react-form-components-guide), the pillar of this category.

## Components in this post

- [PowerPoint Viewer](https://wingo-ui.com/components/pptx-viewer) (Pro): A React PowerPoint (.pptx) viewer with real slides, thumbnails, zoom, search, speaker notes, a single slide view and a fullscreen presenter. Install: `npx wingo-ui@latest add pptx-viewer`
- [DOCX Viewer](https://wingo-ui.com/components/docx-viewer) (Pro): A React Word (.docx) viewer with real pages, headers and footers, thumbnails, zoom, search, comments, tracked changes and download. Install: `npx wingo-ui@latest add docx-viewer`
- [PDF Viewer](https://wingo-ui.com/components/pdf-viewer) (Pro): A React PDF viewer on PDFium: sharp pages, search, thumbnails, rotation, and highlights with notes that export as real PDF annotations. Install: `npx wingo-ui@latest add pdf-viewer`

## FAQ

### How do I show a PowerPoint file in React without a server?

Use a viewer that parses the .pptx in the browser: the file is a zip of XML parts, so it can be unzipped and drawn as HTML and SVG on the device. The Wingo UI PowerPoint Viewer does this; pass a same-origin, CORS-enabled or blob: URL as src and nothing is uploaded.

### Can a React PPTX viewer show speaker notes?

Yes, if it reads the notes parts of the file. The PowerPoint Viewer shows the current slide's notes under it (defaultNotesVisible or the toolbar switch), and its search finds text in the notes as well as on the slides.

### Does the viewer play PowerPoint animations and slide transitions?

No. The PowerPoint Viewer shows each slide in its final state with every shape visible, and video, audio and embedded objects appear as labeled placeholders. If the animations carry the story, share a video or a PDF with one page per build step instead.

### Can React open old .ppt files in the browser?

The PowerPoint Viewer reads .pptx (Office Open XML) only and shows a clear message for .ppt and password-protected files. Convert .ppt on the server, for example with LibreOffice, or look at @extend-ai/react-pptx, whose README says it also reads legacy .ppt.

### Should I convert PowerPoint to PDF for a web app?

Convert when the slides must look identical everywhere, such as signed proposals, archives or decks with unusual fonts. Keep the .pptx when people need the speaker notes, the slide titles as data, or a download of the editable file.

---

Source: https://wingo-ui.com/blog/react-pptx-viewer
