npx shadcn@latest add https://sdk-components.thesqd.com/r/pdf-viewer.jsonreact-pdf — Renders PDF pages as canvas + text layers.import { PdfViewer } from "@/components/ui/pdf-viewer";import { PdfViewer } from "@/components/ui/pdf-viewer";
export function Example() {
return (
<PdfViewer
fileUrl="https://example.com/document.pdf"
height="auto"
/>
);
}PdfViewer (single component — built on react-pdf)
├── fileUrl="…" (any direct PDF URL)
├── height={number | string | "auto"} ("auto" sizes to the document)
├── className="…" (extends the outer container)
├── proxy={false} (skip /api/pdf-proxy for CORS-ready hosts)
├── onPageChange={(page, canvas) => …} (page in view + its drawn canvas)
└── markedPages={[3, 14]} (flag pages in the thumbnail rail)
Built-in chrome:
• Toolbar — full-text search, page "3 / 30", zoom in / out, download
• Opens fitted — the page as large as the view allows, width or height,
whichever comes first; click the % to fit again after zooming
• Sidebar — clickable thumbnails for every page (click to scroll)
• Scroll surface — continuous page list, highlights search matches
Only pages near the view are drawn, and the file is read over range
requests, so page one of a 150 MB booklet costs well under a megabyte.| Prop | Type | Default | Description |
|---|---|---|---|
fileUrl | string | — | Direct URL to the PDF file to render. |
height | number | string | "auto" | 640 | Height of the viewer surface. Numbers are treated as px. Pass "auto" to size the container to the first page; add a max-h-* class (e.g. max-h-[70vh]) and the page is fitted inside that cap, so a landscape page gives a short viewer and a tall one stops at the cap. |
className | string | — | Extends the outer container classes. |
proxy | boolean | true | Route cross-origin URLs through the app's /api/pdf-proxy. Pass false when the host sends CORS headers itself (S3, Wasabi) or the app has no proxy route. |
onPageChange | (page: number, canvas: HTMLCanvasElement | null) => void | — | Fires when the page in view changes and again when it finishes drawing. canvas is null while it draws; read it right away (e.g. to scan a QR code) — it is discarded once the page scrolls away. |
markedPages | readonly number[] | — | Pages to flag with a dot in the thumbnail rail, e.g. the ones a checker had something to say about. |