@extend-ai/react-pptx

中文文档
0.6.0发布于 2026/11/13MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 44.5万

Browser-native, virtualized React viewer for PowerPoint (PPTX, PPT) and OpenDocument (ODP, ODG) presentations

原始使用文档
文档目录14 节
  1. Main API
  2. Responsive zoom
  3. Supported presentation formats
  4. Experimental OpenDocument support
  5. WebAssembly asset
  6. Examples
  7. PowerPoint Viewer
  8. Fonts
  9. Custom scroll areas and hooks
  10. OfficeArt visuals
  11. Presentation metadata
  12. Cold-start thumbnails
  13. Thumbnail hook
  14. Block and word citations

@extend-ai/react-pptx

npm version

Browser-native PowerPoint viewing for React, with experimental OpenDocument support.

npm install @extend-ai/react-pptx

React and React DOM are peer dependencies already present in a React application.

Main API

  • ReactPptxViewer renders URLs, Blob, ArrayBuffer, Uint8Array, parsed presentations, or normalized documents.
  • parsePresentation performs native parsing and returns the same normalized model the viewer renders.
  • initWasm and setWasmSource support eager initialization and custom Wasm/CDN hosting.
  • PptxViewerController provides navigation, zoom, fit, text search, highlighting, model access, and detached thumbnail rendering.

Import @extend-ai/react-pptx/styles.css alongside the component; the stylesheet is emitted as a separate package asset. Parsing and rendering are client-side; importing the JavaScript package during SSR is safe.

Unknown or degraded content is surfaced through onWarning and showDiagnostics rather than silently removed.

Responsive zoom

The viewer accepts the same responsive zoom shape as @extend-ai/react-docx. Numeric values are percentages, while automatic, fit-page, and fit-width remain active as the viewport changes. For example, the shared API can be expressed as:

<Viewer defaultZoom="fit-width" />

With this package's component and required source, use:

<ReactPptxViewer
  source={file}
  defaultZoom="fit-width"
  onZoomChange={({ level, resolvedZoom }) => {
    console.log(level, resolvedZoom);
  }}
/>

automatic shrinks slides that are wider than the viewport without enlarging them. fit-width may enlarge or shrink to fill the available width, and fit-page uses both viewport dimensions. The controller exposes setZoom(level), getZoom(), and getResolvedZoom(), so a custom toolbar can retain the semantic mode while displaying its current percentage. Zooming in or out from a responsive mode should pass getResolvedZoom() + delta to setZoom(), which switches to a numeric level. The older fitMode prop remains supported for compatibility; contain maps to automatic when the new zoom props are absent.

Supported presentation formats

.pptx and legacy PowerPoint 97–2003 .ppt files are both accepted by the same source prop and parsePresentation() API. Legacy files are opened natively from OLE compound storage by the Rust/Wasm parser; the browser does not need LibreOffice, a server-side conversion endpoint, or a temporary .pptx copy.

For .ppt, the parser follows the Current User/UserEditAtom edit chain and live persist-object directory to recover the actual slide list. Supported OfficeArt group and shape anchors, text, pictures, and referenced master drawing content are normalized into the same PresentationDocument consumed by the React viewer. PNG/JPEG pictures render directly, while decoded EMF/WMF records use a bounded browser-side image conversion for static previews.

Legacy rendering is static, not full PowerPoint emulation. Advanced effects, editable binary charts and tables, animations, transitions, active OLE objects, and timed media may degrade to a static picture or remain unsupported. Inspect onWarning or enable showDiagnostics to receive explicit degraded-rendering warnings:

<ReactPptxViewer
  source={file}
  showDiagnostics
  onWarning={(warning) => {
    if (warning.code === 'degraded-rendering') {
      console.warn(warning.message, warning.slideIndex);
    }
  }}
/>

The repository regression suite opens a real three-slide PowerPoint 97–2003 file at tests/fixtures/legacy/file-example-250kb.ppt directly in Rust and the playground. It checks slide order, text, normalized nodes, thumbnail navigation, and diagnostics without a conversion step.

Experimental OpenDocument support

OpenDocument presentations (.odp, .otp, .fodp) and drawings (.odg, .otg, .fodg) are accepted by the same source prop and parsePresentation() API. The Rust/Wasm parser detects the format from the bytes and returns document.format as odp or odg. Drawing pages are displayed as slides. These formats are view only.

Supported charts render from their data, and custom drawing shapes use enhanced geometry where supported. Support is experimental: rendering fidelity varies, especially for chart layouts and custom shapes, and some content remains unsupported. See the OpenDocument support guide for details.

WebAssembly asset

Native PowerPoint parsing runs through a WebAssembly module that loads lazily. Most apps can use the default loader. If your bundler or deployment needs to host the binary explicitly, configure it before the first presentation is parsed:

import { setWasmSource } from '@extend-ai/react-pptx';

setWasmSource('https://cdn.example.com/pptx_wasm_bg.wasm');
// A URL, Request, Response, ArrayBuffer/TypedArray, or WebAssembly.Module also works.

The binary is also available as a package subpath for bundlers that support asset URL imports:

import wasmUrl from '@extend-ai/react-pptx/pptx_wasm_bg.wasm?url';
import { setWasmSource } from '@extend-ai/react-pptx';

setWasmSource(wasmUrl);

Configured strings, URLs, request URLs, bytes, and WebAssembly.Module values are forwarded to the parser worker. A Response is supported on the main thread because it cannot be forwarded reliably to a worker. initWasm() optionally accepts the same source when eager initialization is useful.

Examples

See @extend-ai/react-pptx in action in these live Extend UI examples. Click a screenshot to open the demo and integration docs.

PowerPoint Viewer

Explore slide navigation, zoom, and presentation previews.

PowerPoint viewer with a presentation slide and navigation controls

Fonts

Fonts embedded in a .pptx are decoded by the Rust parser and registered before the first slide is rendered. Applications can also provide licensed/self-hosted fonts. The viewer preserves the requested PowerPoint family, then appends Office-compatible and script-complete fallbacks for Latin, CJK, Arabic, Hebrew, emoji, and math glyphs.

<ReactPptxViewer
  source={file}
  fonts={{
    sources: [
      { family: 'Brand Sans', source: '/fonts/brand-sans.woff2' },
      {
        family: 'Brand Sans',
        source: '/fonts/brand-sans-bold.woff2',
        descriptors: { weight: '700' },
      },
    ],
    fallbacks: { 'Brand Sans': ['Inter', 'Arial'] },
    fallbackFamilies: ['Noto Sans', 'Noto Sans CJK SC', 'Noto Sans Arabic'],
  }}
  onWarning={(warning) => {
    if (warning.code === 'missing-font') console.warn(warning.message);
  }}
/>

The viewer bundles shared fallbacks for Calibri, Arial, Times New Roman, Courier New, Aptos and Aptos Narrow. It loads requested families before layout and prefers embedded, caller-provided and installed originals. Each family is a lazy chunk; deploy all generated chunks alongside the viewer. Set fonts.useOfficeFallbacks to false to disable automatic fallback loading. Redistribution notices are in dist/Office-Font-Licenses.txt.

The package does not redistribute proprietary Microsoft fonts. Other families depend on embedded fonts or fonts supplied by the host. resolvePptxFontFamily() and OFFICE_FONT_FALLBACKS are exported for applications that render presentation text outside the viewer.

Custom scroll areas and hooks

Pass the actual scrolling viewport through virtualization.scrollElement. This works with Radix, Base UI, coss, or any host-owned scroll area and makes that element the observer root.

const [scrollElement, setScrollElement] = useState<HTMLDivElement | null>(null);
const viewer = usePptxViewer();
const parsed = usePptxPresentation(file);

return (
  <ScrollArea.Root>
    <ScrollArea.Viewport ref={setScrollElement}>
      {parsed.presentation ? (
        <ReactPptxViewer
          ref={viewer.ref}
          source={parsed.presentation}
          virtualization={{ enabled: true, overscanViewport: 2, scrollElement }}
        />
      ) : null}
    </ScrollArea.Viewport>
  </ScrollArea.Root>
);

usePptxPresentation (usePptxModel alias) separates parsing from rendering, while usePptxViewer exposes the reactive navigation/search/zoom controller. onViewportReady provides the internal slide surface for advanced integrations and test harnesses.

OfficeArt visuals

Pictures, supported shapes, connectors, and saved SmartArt drawings use the shared Rust OfficeArt renderer. SmartArt text retains its saved text frame separately from the shape frame, including independent offsets, dimensions, rotation, and flips. Semantic data without a supported saved drawing remains an explicit layout fallback.

Presentation metadata

The model carries PowerPoint data beyond the drawn slide so hosts can build their own behaviour on it. Slides, layouts and masters expose transition and timing (the parsed p:transition and p:timing parts, including animation nodes, targets and build lists), text runs expose math (Office Math with a MathML rendering) and field (slide numbers, dates and other fields with their cached text), table cells expose merge, and every node may carry clickAction, hoverAction, editing (locks and connector endpoints), accessibilityTitle, description and decorative. Media nodes expose playback trims and bookmarks, a poster frame, and embeddedObject details for OLE objects and controls. The viewer renders math as MathML, skips merged cells, navigates presentation jump and slide-link actions in place, and shows poster frames with a play control; it does not play transitions or animation timelines.

parsePresentation(source, { include3dModels: true }) includes original embedded 3D model bytes and content type, model and preview relationships, and scene XML in ImageNode.model3d. The option also works through ReactPptxViewer's parseOptions and the parsing hook. It defaults to false; cached Office raster previews remain the rendered appearance. This metadata does not add an interactive 3D renderer.

Cold-start thumbnails

createPptxThumbnailRenderer renders directly from a ParsedPresentation; it does not mount or initialize ReactPptxViewer. One renderer reuses its font manager, DOM/SVG rendering context, and presentation asset cache across slide requests. The parsed presentation can later be passed to ReactPptxViewer without fetching or parsing it again.

import { createPptxThumbnailRenderer, parsePresentation } from '@extend-ai/react-pptx';

const presentation = await parsePresentation(source, {
  onPerformanceMeasurement: recordMeasurement,
});
const renderer = createPptxThumbnailRenderer(presentation, {
  fonts: {
    loadEmbeddedFonts: false,
    waitForFonts: false,
  },
  concurrency: 2,
  onPerformanceMeasurement: recordMeasurement,
});

const thumbnail = await renderer.renderSlide(0, {
  maxWidth: 240,
  maxHeight: 135,
  output: 'blob',
  signal: abortController.signal,
});

image.src = URL.createObjectURL(thumbnail.data);
renderer.destroy();

The output can be blob (PNG, the default), canvas, imageBitmap, or svg. renderSlides() accepts an explicit index list, preserves its order, and never initializes other slides. Both single and batch requests use the renderer's bounded queue. By default, the thumbnail-specific font policy skips embedded fonts, global font readiness, and missing-font probing; callers can opt back into any of those behaviors through fonts.

Performance observers receive download, wasm-parsing, embedded-font-preparation, slide-dom-svg-rendering, image-decoding, and raster-encoding measurements as applicable. Each render result also contains its slide-specific measurements.

Thumbnail hook

usePptxViewerThumbnails exposes detached slide previews for a consumer-owned filmstrip. PPTX thumbnails use the same live DOM/SVG renderer and loaded fonts as the main viewer, so attach each stable containerRef to a regular element rather than a canvas.

import { ReactPptxViewer, usePptxViewer, usePptxViewerThumbnails } from '@extend-ai/react-pptx';

export function PresentationWithThumbnails({ file }: { file: ArrayBuffer }) {
  const viewer = usePptxViewer();
  const { thumbnails } = usePptxViewerThumbnails(viewer.controller, {
    resolution: { maxWidth: 180, maxHeight: 120 },
    renderWindow: {
      visibleSlideIndexes: [0, 1, 2],
      prefetchSlideIndexes: [3, 4, 5],
    },
  });

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '200px 1fr', gap: 16 }}>
      <aside style={{ display: 'grid', gap: 12, alignContent: 'start' }}>
        {thumbnails.map((thumbnail) => (
          <button
            key={thumbnail.slideIndex}
            type="button"
            onClick={() => void viewer.controller?.goToSlide(thumbnail.slideIndex)}
          >
            <div
              ref={thumbnail.containerRef}
              style={{
                width: thumbnail.width,
                height: thumbnail.height,
                overflow: 'hidden',
              }}
            />
          </button>
        ))}
      </aside>
      <ReactPptxViewer ref={viewer.ref} source={file} mode="slide" />
    </div>
  );
}

The result also provides renderThumbnail(slideIndex, element) for imperative integrations and rerenderAttachedThumbnails() for refreshing every currently attached preview. disabled keeps the metadata stable while pausing and disposing thumbnail rendering. For large decks, virtualize the rail against its actual scroll element: mount containerRef only for virtual rows, pass those rows through renderWindow.visibleSlideIndexes, and use prefetchSlideIndexes to warm nearby slides. The built-in showThumbnails filmstrip follows the same windowed behavior.

Block and word citations

The bundled runtime uses the Rust 0.4.1 parser and block extractor, with rust-odf 0.2.0, rust-office-art 0.1.9 and rust-office-charts 0.2.0. Call extractPresentationBlocks(parsed.document, { includeWords: true }), then pass its blocks or words to PptxBlockHighlights or PptxWordHighlights. The components accept a viewer rootRef, selected target, optional multiple targets, color and an onGeometry callback for the selected target, following the React DOCX API.

resolvePptxSourceGeometry, resolvePptxBlockGeometries and resolvePptxWordGeometries return axis-aligned slide-relative fragments with explicit rendered, unmounted, invisible or unresolved states. revealPptxSource(controller, root, ref) mounts and navigates to the referenced slide. normalizedPptxBoundingBox converts a fragment to fractional slide coordinates.

References carry document identity, slide and node paths, optional cell/paragraph indices and UTF-16 text offsets. Preserve them with extracted content; matching visible text alone cannot distinguish repeated occurrences. Geometry is limited to mounted slide content. Notes, chart-label subranges and mathematical subranges do not receive invented rectangles.

See the citation guide for usage and the playground Blocks view.

版本与发布记录

@extend-ai/react-pptx 共发布 14 个版本,首次发布于 2026/07/17;过去 12 个月发布了 14 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.6.0latest2026/11/13今天
0.5.02026/11/122 天前
0.4.12026/11/104 天前
0.4.02026/11/104 天前
0.3.02026/11/085 天前
0.2.52026/11/068 天前

关于 @extend-ai/react-pptx 的常见问题

@extend-ai/react-pptx 是什么?

Browser-native, virtualized React viewer for PowerPoint (PPTX, PPT) and OpenDocument (ODP, ODG) presentations

如何安装 @extend-ai/react-pptx?

在项目目录运行 npm install @extend-ai/react-pptx,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(>=18.2 <20)、react-dom(>=18.2 <20)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@extend-ai/react-pptx 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@extend-ai/react-pptx 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@extend-ai/react-pptx 可以商用吗?

@extend-ai/react-pptx 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@extend-ai/react-pptx 的下载量有多少?

根据 npm 官方下载统计,@extend-ai/react-pptx 在 2026/10/14 – 2026/11/12 这 30 天内被下载 444,747 次,日均约 14,825 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@extend-ai/react-pptx 还在维护吗?

最新版本 0.6.0 发布于 2026/11/13(今天);至今共发布 14 个版本,其中过去 12 个月发布了 14 个;首次发布于 2026/07/17。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。