- PDF Viewer
- PDF Toolbar
- PDF More Actions Menu
- PDF Floating Toolbar
- PDF Document Tabs
- PDF View
- PDF Document Grid
- PDF Document Info
- PDF Page Navigation
- PDF Zoom Controls
- PDF Undo/Redo Buttons
- PDF Keyboard Shortcuts
- PDF Bookmark Sidebar
- PDF Thumbnail Sidebar
- PDF Search Panel
- PDF Attachment List
- PDF Annotation Layer
- PDF Annotation Toolbar
- PDF Annotation Inspector
- PDF Annotation Selection Menu
- PDF Annotation Sidebar
- PDF Comment
- PDF Comment Draft
- PDF Comment Button
- PDF Comment Sidebar
- PDF Redaction Toolbar
- PDF Capture Button
- PDF Form Fill Toggle
- PDF Signature Button
- PDF Stamp Button
pdfcn is distributed through shadcn/ui's registry system. Set up shadcn/ui in your project first by following the official installation guide for your framework.
Requirements#
- A project set up with shadcn/ui (Tailwind CSS v4 and React 19).
- Components are built on embedpdf plugins and compose core shadcn/ui components. Both are installed for you by the CLI.
- A bundler that can serve a
.wasmfile. The engine loads PDFium from yourpublic/folder.
Installing components#
Every component can be installed with the shadcn CLI by pointing at this registry:
pnpm dlx shadcn@latest add pdfcn/viewer
Installing viewer pulls in its dependencies automatically — the use-engine hook, the pdfium.wasm binary, and the shadcn/ui components it composes. Each component's documentation page includes its exact install command, along with a manual installation option if you prefer to copy the source directly.
Rendering a document#
<PdfViewer> provides the engine and the plugin registry; <PdfViewerContent> renders the page stack against it.
pnpm dlx shadcn@latest add pdfcn/viewer-content
import { PdfViewer } from "@/components/pdf-viewer";
import { PdfViewerContent } from "@/components/pdf-viewer-content";
export function MyViewer() {
return (
<PdfViewer documents={[{ url: "/sample.pdf" }]} className="h-[720px]">
<PdfViewerContent />
</PdfViewer>
);
}<PdfViewer /> fills its parent, so give it a height — it collapses to nothing without one.
<PdfViewer> touches window and Worker on mount. When rendering it
inside a Server Component tree, load it through next/dynamic(() => import(...), { ssr: false }) — see the PDF
Viewer page for a working example.
The WASM binary#
The use-engine item copies pdfium.wasm into your project's public/ folder, and usePdfEngine fetches it from /pdfium.wasm by default. Pass a wasmUrl to load it from somewhere else, such as a CDN:
const { engine } = usePdfEngine({
wasmUrl: "https://cdn.example.com/pdfium.wasm",
});How the engine runs PDFium in a Web Worker and loads that binary is embedpdf's; usePdfEngine is a thin shim over its usePdfiumEngine hook, documented in full there.
Adding chrome#
Toolbars and sidebars read the active document from <PdfViewer>'s context, so they can be added anywhere inside the tree without extra props:
pnpm dlx shadcn@latest add pdfcn/toolbar pdfcn/zoom-controls
<PdfViewer documents={[{ url: "/sample.pdf" }]} className="h-[720px]">
<PdfToolbar>
<PdfPageNavigation />
<PdfToolbarSeparator />
<PdfZoomControls />
</PdfToolbar>
<PdfViewerContent />
</PdfViewer>See Components for what's available and how each one is registered.