- 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
"use client";
import { PdfBookmarkSidebar } from "@/components/pdf-bookmark-sidebar";About#
<PdfBookmarkSidebar /> reads the outline a PDF ships with — the tree of titles its author wrote into the file — and turns each entry into a button that scrolls the viewer to its destination.
Many PDFs have no outline, so the sidebar shows an empty state rather than collapsing the column out of your layout.
Installation#
pnpm dlx shadcn@latest add pdfcn/bookmark-sidebar
Usage#
import { PdfBookmarkSidebar } from "@/components/pdf-bookmark-sidebar";<PdfViewer documents={[{ url: "/sample.pdf" }]} className="h-[600px] flex-row">
<PdfBookmarkSidebar className="w-56 shrink-0 border-r" />
<PdfViewerContent />
</PdfViewer><PdfViewer /> is a flex column by default, which stacks a sidebar above the document. Override it with flex-row to put them side by side, and give the sidebar a width — it fills its parent's height but has no width of its own.
The bookmark plugin is part of the light tier <PdfViewer /> already registers, so nothing needs to be added to plugins.
Examples#
Default#
"use client";
import { PdfBookmarkSidebar } from "@/components/pdf-bookmark-sidebar";Accessibility#
The list is wrapped in a <nav aria-label="Document outline"> so it's reachable as a landmark, and rendered as nested <ul>/<li> elements so the outline's depth is conveyed structurally rather than by indentation alone. Every entry is a real <button>, reachable with Tab.
Entries that point at something other than a page destination — an external URL, an embedded action — are rendered disabled rather than hidden, so the outline still matches the document's own structure.
API Reference#
PdfBookmarkSidebar#
A <ScrollArea /> carrying data-slot="pdf-bookmark-sidebar", containing the outline tree. Accepts every <ScrollArea /> prop.
Fetches the outline once per document through the bookmark plugin's capability, and scrolls the viewer via useScroll when an entry is clicked. It has no width of its own and fills its parent's height.
The sidebar renders in three states, all at the same size: empty while the document loads, a message when the document has no outline, and the tree itself otherwise.
Styling the tree#
The rendered markup carries slots at each level, so the tree can be restyled without forking the component:
| Slot | Element | Description |
|---|---|---|
pdf-bookmark-sidebar | div | The scroll container. |
pdf-bookmark-list | ul | One per level, including the root. |
pdf-bookmark-item | button | A single outline entry. |
Nested lists are indented with a left border. Depth is unbounded — the list renders itself recursively for as many levels as the document declares.