EmbedPDF

Build your own PDF viewer

The headless packages give you everything a PDF viewer does, without a look of their own: pages that scroll and zoom, crisp rendering, text selection and search, annotations, forms and signatures. You build the interface in React, and nothing appears on screen unless you put it there.

overview.tsx
import { Viewer, DocumentGate } from '@embedpdf/react/runtime';
import { Stage, stagePlugin } from '@embedpdf/react/stage';
import { RenderLayer, renderPlugin } from '@embedpdf/react/render';
import { localEngine } from '@embedpdf/engine';

const engine = localEngine();
const plugins = [stagePlugin(), renderPlugin()];

export function App() {
  return (
    <Viewer
      engine={engine}
      plugins={plugins}
      initialDocuments={[{ source: { kind: 'url', url: '/contract.pdf' } }]}
    >
      <DocumentGate fallback={<p>Opening…</p>}>
        <Stage style={{ height: 600 }}>{() => <RenderLayer />}</Stage>
      </DocumentGate>
    </Viewer>
  );
}

That’s a complete viewer: the pages scroll, zoom with a pinch or Ctrl and the wheel, and stay sharp at every zoom. Everything else is a plugin you add, and a few lines of your own UI.

Headless or the ready-made Viewer?#

EmbedPDF comes in two forms, built on the same engine and plugins:

  • The Viewer is finished: a toolbar, sidebars, annotation tools and search, ready in minutes. You configure it and theme it.
  • Headless is the parts: you decide what the toolbar looks like, where the search box goes, and what happens when someone clicks an annotation.

Choose headless when the viewer is part of your product’s own interface. You can start with the Viewer and move to headless later: the plugins and their options are the same.

How it’s put together#

A headless viewer has five parts. You meet them on every page:

  • The engine opens and reads PDF files. It runs in the browser, or on your server with CloudPDF.
  • <Viewer> starts the engine, opens documents, and holds the plugins.
  • Plugins add one feature each: search, annotations, forms. Register the ones you need; the rest never reach your bundle.
  • Layers draw inside each page: the page itself, the text selection, the annotations.
  • Hooks connect your own UI: useSearch() to search, useSearchState() to show the results, useSearchEvent() to react when something happens.

How it works explains each in a few minutes.

Every plugin#

Each plugin is one import line. Registering a plugin and importing its components come from the same place:

PluginWhat it gives youImport from
StageScrolling, zoom, layouts, page navigation@embedpdf/react/stage
RenderSharp pages at every zoom, deep-zoom tiles@embedpdf/react/render
LinksClickable links to pages and websites@embedpdf/react/link
SelectionSelecting and copying text@embedpdf/react/selection
SearchFinding text, and showing every match@embedpdf/react/search
AnnotationsHighlights, notes, shapes, free text, and your own tools@embedpdf/react/annotation
StampsLibraries of stamps, placed by click or by code@embedpdf/react/stamp
MeasurementsDistances, perimeters and areas at a real scale@embedpdf/react/measurement
RedactionRemoving content for good@embedpdf/react/redaction
FormsFilling and building PDF forms@embedpdf/react/form
SignaturesSigning documents and checking signatures@embedpdf/react/signature
Page editRotating, reordering, inserting and deleting pages@embedpdf/react/page-edit
MetadataA document’s title, author and your own fields@embedpdf/react/metadata
ActionsWhat a PDF does by itself: buttons, scripts, printing@embedpdf/react/actions
View managerSeveral documents side by side@embedpdf/react/view-manager
InteractionThe active tool, cursors and touch@embedpdf/react/interaction
CommandsNamed actions with labels, icons and shortcuts@embedpdf/react/commands
ShellWhich panels, dialogs and menus are open@embedpdf/react/shell
TranslationsYour UI in the user’s language@embedpdf/react/i18n

Local or cloud#

The same viewer runs on either engine. Only how you create the engine and open a document differs; every plugin, hook and component stays the same.

The local engine runs in the browser: no server, no upload, and it works offline. It’s the right choice when the user already has the file, or when the file may not leave their device.

Next steps#

Was this page helpful?

Your feedback goes directly to the documentation team.