Minimal, client-only test project that composes a headless PDF viewer with EmbedPDF core + engine + plugins.
npm installIf you prefer explicit packages:
npm install \
@embedpdf/core @embedpdf/engines \
@embedpdf/plugin-document-manager @embedpdf/plugin-viewport @embedpdf/plugin-scroll @embedpdf/plugin-render \
@embedpdf/plugin-interaction-manager @embedpdf/plugin-selection \
@embedpdf/plugin-annotation @embedpdf/plugin-history \
@embedpdf/plugin-zoom @embedpdf/plugin-search @embedpdf/plugin-fullscreennpm run dev- Engine:
usePdfiumEngine()from@embedpdf/enginescreates a client-side PDFium engine instance. - Plugins:
createViewerPlugins()insrc/pdf/plugins.tsregisters core plugins + feature plugins in the recommended order. - Viewer tree:
<EmbedPDF>provides context + plugin registry<DocumentContent>loads the active document
<Viewport>+<Scroller>handle layout and pagingrenderPage()composes layers inside<PagePointerProvider>:<RenderLayer><SelectionLayer><AnnotationLayer><MarqueeZoom><SearchLayer>
- Add the plugin package registration in
src/pdf/plugins.ts. - If the plugin has a render layer, add it to
renderPage()insrc/pdf/PDFViewer.tsx. - Add UI (controls/hooks) under
src/pdf/toolbar/.
Annotation state is persisted to localStorage in useAnnotationPersistence() (src/pdf/hooks/useAnnotationPersistence.ts).
Storage key is derived from the document URL when available.
- Search/fullscreen hook names are assumed from EmbedPDF's headless patterns. If the package exports differ, update
src/pdf/toolbar/SearchBar.tsxandsrc/pdf/toolbar/FullscreenButton.tsxaccordingly. - Local file persistence uses the document name/id if no URL is available.
- PDF renders
- Text selection overlay
- Highlight + underline annotations
- Zoom controls
- Marquee (area) zoom toggle
- Search UI (next/prev + count)
- Fullscreen toggle
- Annotation persistence (localStorage)