- 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
A grid of every open document, each card a navigable single-page preview that opens the document when picked.
"use client";
import { PdfDocumentGrid } from "@/components/pdf-document-grid";About#
<PdfDocumentGrid /> shows every open document as a card in a responsive grid.
It renders each preview off embedpdf's
thumbnail plugin, which can
render any loaded document by id — so every card shares the one engine
<PdfViewer> already runs, instead of spinning up a viewer per document.
- Preview — each card renders one page of its document. Paging a card is local: it flips through that document's pages without touching the viewer, so the grid works as a browsable overview.
- Select — clicking a card routes it through the
view-manager into the
shared view, so the
<PdfViewer>(and every control bound to it) switches to that document. The selected card carries a ring. - Open more — a trailing card calls the document-manager's file dialog, and the newly opened document joins the grid.
The thumbnail, view-manager, and document-manager plugins all ship inside
<PdfViewer> already, so the grid needs no extra plugin registration.
Installation#
pnpm dlx shadcn@latest add pdfcn/document-grid
Usage#
Place <PdfDocumentGrid> inside a <PdfViewer> loaded with multiple
documents, beside the viewer it drives.
<PdfViewer
documents={[{ url: "/sample.pdf" }, { url: "/form.pdf" }]}
className="h-[720px]"
>
<div className="flex h-full min-h-0">
<PdfDocumentGrid className="w-2/5 border-r" />
<div className="flex min-w-0 flex-1 flex-col">
<PdfToolbar>
<PdfPageNavigation />
<PdfZoomControls />
</PdfToolbar>
<PdfViewerContent />
</div>
</div>
</PdfViewer>Examples#
Default#
Three documents load into the grid, beside a viewer. Page through a card in place, then click it to open that document in the viewer — the ring follows the open document. The trailing card opens another PDF into the grid.
"use client";
import { PdfDocumentGrid } from "@/components/pdf-document-grid";As a launcher#
Pass onSelectDocument to react when a card is picked — the
library app block uses it to swap the grid for a
full-screen reader of the chosen document, then back again.
const [mode, setMode] = React.useState<"library" | "reader">("library");
return mode === "library" ? (
<PdfDocumentGrid onSelectDocument={() => setMode("reader")} />
) : (
<Reader onBack={() => setMode("library")} />
);Accessibility#
Each card is a button labelled Open <name>, with focus-visible rings on both
the preview and the page-step controls. The page steppers are labelled
"Previous page" and "Next page" and stop the click from bubbling into the
card's select, so paging never opens the document. The trailing card is labelled
"Open another PDF".
API Reference#
PdfDocumentGrid#
A <div> carrying data-slot="pdf-document-grid". Enumerates every open
document and renders each as a card. Accepts every prop a <div> takes, plus:
| Prop | Type | Default | Description |
|---|---|---|---|
minCardWidth | number | 200 | Smallest a card gets before the grid drops a column, in pixels. Drives the layout. |
gap | number | 16 | The gutter between cards, in pixels. |
showAddCard | boolean | true | Render the trailing card that opens another document. |
onSelectDocument | (documentId: string) => void | Called with a document's id when its card is picked, after selection is routed. |