A desk with a monitor showing a PDF viewer interface

EmbedPDF: Chrome's Own PDF Engine, Now in Your App

The Orange Cat
The Orange Cat

If you have ever tried to embed a PDF in a web application, you know the pain. iframes feel like duct tape, PDF.js demands a mountain of custom UI work, and most React wrappers stop at basic page rendering. EmbedPDF takes a different approach entirely. It ships Google Chrome's own PDFium engine as a WebAssembly module and wraps it in a plugin-based architecture that works with React, Vue, Svelte, or plain JavaScript. Whether you want a polished viewer in two lines of code or a fully bespoke reading experience, EmbedPDF has a path for you.

What Makes It Tick

EmbedPDF stands out from the crowd with a set of capabilities that most PDF libraries simply do not offer:

  • PDFium via WebAssembly -- the same rendering engine behind Chrome's built-in PDF viewer, compiled to run entirely in the browser with near-native speed
  • Two integration modes -- a drop-in snippet for instant embedding, or a headless plugin system for full UI control
  • Tree-shakable plugins -- viewport, scroll, render, annotations, redaction, search, zoom, bookmarks, and more, each loaded only when needed
  • Framework-agnostic -- first-class support for React, Vue, Svelte, Preact, and vanilla JS
  • True redaction -- not a visual overlay but actual content removal from the PDF
  • Annotations -- highlights, sticky notes, free text, and ink drawing built in
  • Multi-document support -- open several PDFs in tabs within a single viewer instance
  • Internationalization -- community translations plus CJK and RTL font fallback packages

Getting Started

The Quick Route: Snippet Mode

If all you need is a working PDF viewer with a full UI, @embedpdf/snippet is the fastest path.

npm install @embedpdf/snippet
# or
yarn add @embedpdf/snippet

Drop it into your page and you get zoom controls, search, annotations, print, and page navigation out of the box.

The Full Toolkit: Headless Mode

For a custom viewer in React, you will need the core packages plus whichever plugins your use case demands.

npm install @embedpdf/core @embedpdf/engines @embedpdf/pdfium \
  @embedpdf/plugin-document-manager @embedpdf/plugin-viewport \
  @embedpdf/plugin-scroll @embedpdf/plugin-render
yarn add @embedpdf/core @embedpdf/engines @embedpdf/pdfium \
  @embedpdf/plugin-document-manager @embedpdf/plugin-viewport \
  @embedpdf/plugin-scroll @embedpdf/plugin-render

Your First Custom Viewer

Wiring Up the Engine

The PDFium engine loads asynchronously since it needs to fetch and initialize the WebAssembly binary. The usePdfiumEngine hook handles this lifecycle for you in React.

import { usePdfiumEngine } from '@embedpdf/engines/react';

const MyViewer = () => {
  const { engine, isLoading } = usePdfiumEngine();

  if (isLoading || !engine) {
    return <div>Loading PDF engine...</div>;
  }

  return <PDFCanvas engine={engine} />;
};

Registering Plugins

Every feature in headless mode is a plugin. You compose them with createPluginRegistration and pass the resulting array to the <EmbedPDF> provider.

import { createPluginRegistration } from '@embedpdf/core';
import { EmbedPDF } from '@embedpdf/core/react';
import { DocumentManagerPluginPackage } from '@embedpdf/plugin-document-manager/react';
import { ViewportPluginPackage } from '@embedpdf/plugin-viewport/react';
import { ScrollPluginPackage } from '@embedpdf/plugin-scroll/react';
import { RenderPluginPackage } from '@embedpdf/plugin-render/react';

const plugins = [
  createPluginRegistration(DocumentManagerPluginPackage, {
    initialDocuments: [{ url: '/quarterly-report.pdf' }],
  }),
  createPluginRegistration(ViewportPluginPackage),
  createPluginRegistration(ScrollPluginPackage),
  createPluginRegistration(RenderPluginPackage),
];

Rendering Pages

With plugins registered, you compose the viewer from a handful of React components. The <Viewport> manages the scrollable container, <Scroller> handles virtualized page layout, and <RenderLayer> paints each page onto a canvas.

import { EmbedPDF } from '@embedpdf/core/react';
import { DocumentContent } from '@embedpdf/plugin-document-manager/react';
import { Viewport } from '@embedpdf/plugin-viewport/react';
import { Scroller } from '@embedpdf/plugin-scroll/react';
import { RenderLayer } from '@embedpdf/plugin-render/react';

const PDFCanvas = ({ engine }) => (
  <div style={{ height: '600px' }}>
    <EmbedPDF engine={engine} plugins={plugins}>
      {({ activeDocumentId }) =>
        activeDocumentId && (
          <DocumentContent documentId={activeDocumentId}>
            {({ isLoaded }) =>
              isLoaded && (
                <Viewport documentId={activeDocumentId}>
                  <Scroller
                    documentId={activeDocumentId}
                    renderPage={({ width, height, pageIndex }) => (
                      <div style={{ width, height }}>
                        <RenderLayer
                          documentId={activeDocumentId}
                          pageIndex={pageIndex}
                        />
                      </div>
                    )}
                  />
                </Viewport>
              )
            }
          </DocumentContent>
        )
      }
    </EmbedPDF>
  </div>
);

Going Deeper

Adding Annotations

The annotation plugin unlocks highlights, sticky notes, free text overlays, and freehand ink drawing. Install it and register it alongside your other plugins.

npm install @embedpdf/plugin-annotation
import { AnnotationPluginPackage } from '@embedpdf/plugin-annotation/react';

const plugins = [
  // ...existing plugins
  createPluginRegistration(AnnotationPluginPackage),
];

With the annotation plugin active, you can layer annotation UI on top of the rendered pages. The plugin exposes hooks for creating, updating, and deleting annotations programmatically, so you can build exactly the toolbar or sidebar your application needs.

Search and Text Selection

Full-text search comes via the search plugin. It leverages PDFium's text extraction under the hood, which means it can find text even in PDFs where other JavaScript-based engines struggle with complex glyph mappings.

npm install @embedpdf/plugin-search
import { SearchPluginPackage } from '@embedpdf/plugin-search/react';

const plugins = [
  // ...existing plugins
  createPluginRegistration(SearchPluginPackage),
];

Redacting Sensitive Content

Unlike most PDF libraries that merely draw a black rectangle over text, the redaction plugin in EmbedPDF permanently removes the underlying content from the document. This is critical for legal, medical, and financial applications where a visual overlay is not sufficient.

npm install @embedpdf/plugin-redaction
import { RedactionPluginPackage } from '@embedpdf/plugin-redaction/react';

const plugins = [
  // ...existing plugins
  createPluginRegistration(RedactionPluginPackage),
];

Once a redaction is applied and the document is saved, the original text is gone for good. No copy-pasting behind the black box, no metadata leaks.

PDFium vs PDF.js: Why It Matters

Most open-source PDF viewers in the JavaScript ecosystem are built on Mozilla's PDF.js. It is a solid engine, but it was designed as a JavaScript implementation of the PDF specification. EmbedPDF takes a fundamentally different approach by wrapping PDFium, which is the C++ engine that Google maintains for Chrome. Compiled to WebAssembly, it delivers rendering fidelity that matches what you see when you open a PDF in Chrome natively. For documents with complex fonts, embedded forms, or unusual encoding, this difference can be dramatic.

The trade-off is that PDFium ships as a WebAssembly binary, which adds to the initial download. But once loaded, rendering and text extraction run at near-native speed, and the plugin architecture means you never load more than you actually use.

Wrapping Up

EmbedPDF fills a gap that has existed in the JavaScript PDF ecosystem for a long time. It gives you Chrome-quality PDF rendering in a modular, framework-agnostic package that scales from a two-line embed to a fully custom document viewer. The plugin system keeps bundles lean, the annotation and redaction features cover real enterprise needs, and the active release cadence (weekly updates, 3,400+ GitHub stars in its first year) signals a project with serious momentum. If your application needs to do more with PDFs than just display pages, this library deserves a close look.