- 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
An overflow menu for the toolbar actions that don't earn an icon, plus the document properties dialog it opens.
"use client";
import { PdfMoreActionsMenu } from "@/components/pdf-more-actions-menu";About#
<PdfMoreActionsMenu /> is the "⋮" at the end of a toolbar: print, first and last page, rotation, scroll direction, pan, page layout, presentation mode, opening a file, and document properties. It's one control over eight plugin hooks, for the actions a toolbar can't spare an icon for.
Every item here also exists as a standalone control — <PdfRotateButton />, <PdfSpreadToggle />, <PdfPanToggle />, <PdfPrintButton />, <PdfFullscreenToggle />, <PdfOpenFileButton />. This is a second composition over the same hooks, not a replacement for them. Render whichever fits the width you have.
Every plugin this menu drives ships inside <PdfViewer /> already, so adding
it doesn't change which plugins load.
Installation#
pnpm dlx shadcn@latest add pdfcn/more-actions-menu
Usage#
import { PdfMoreActionsMenu } from "@/components/pdf-more-actions-menu";<PdfViewer documents={[{ url: "/sample.pdf" }]} className="h-[720px]">
<PdfToolbar>
<PdfPageNavigation />
<PdfToolbarSeparator />
<PdfZoomControls />
<PdfMoreActionsMenu className="ml-auto" />
</PdfToolbar>
<PdfViewerContent />
</PdfViewer>The root renders no element of its own, so className lands on the "⋮" trigger — the only part a layout needs to position.
<PdfDocumentPropertiesDialog /> ships in the same file. The menu mounts it itself, because "Document properties…" needs somewhere to go; you only import it separately to put the dialog in a toolbar without the rest of the menu.
Examples#
Default#
"use client";
import { PdfMoreActionsMenu } from "@/components/pdf-more-actions-menu";Single-document viewer#
closeExisting closes what's open before the picker appears, so exactly one document ends up loaded. It mirrors <PdfOpenFileButton />'s prop of the same name, and it's how the viewer app keeps a single-document layout single.
<PdfMoreActionsMenu closeExisting />Leave it off for a tabbed host like the workspace app, where a new file should open alongside what's already there.
Properties without the menu#
The dialog stands alone as its own icon button, for a toolbar wide enough to show properties directly:
<PdfToolbar>
<PdfPageNavigation />
<div className="ml-auto flex items-center gap-1">
<PdfDocumentPropertiesDialog />
<PdfPrintButton />
</div>
</PdfToolbar>Pass trigger to open it from something else — a menu item, a link, a button of your own:
<PdfDocumentPropertiesDialog
trigger={<Button variant="outline">Details</Button>}
/>Accessibility#
The trigger is a real <button> carrying aria-label="Open more actions menu", matching its tooltip, so the label is available whether or not the tooltip is shown.
The menu itself is shadcn's <DropdownMenu />: ↑ and ↓ move between items, Enter activates, Esc closes and returns focus to the trigger. Presentation mode and pan are checkbox items; scroll direction and page layout are radio groups, so a screen reader announces which of each set is current.
Items whose plugin isn't ready — or whose document hasn't loaded — render disabled rather than absent, so the menu keeps its shape and its item order as a document opens.
"Document properties…" opens its dialog a tick after the menu closes. Opening both in the same tick races the menu returning focus to its trigger against the dialog trapping it, and focus can end up on a menu that's already gone.
API Reference#
PdfMoreActionsMenu#
A <DropdownMenu /> whose trigger is a ghost icon button carrying data-slot="pdf-more-actions-menu-trigger". Accepts every <DropdownMenu /> prop, plus:
| Prop | Type | Default | Description |
|---|---|---|---|
closeExisting | boolean | false | Close every open document before showing the file picker, so exactly one ends up loaded. |
className | string | — | Applied to the "⋮" trigger. The root renders no element of its own. |
PdfDocumentPropertiesDialog#
A <Dialog /> of the active document's PDF properties. The property list inside is <PdfDocumentInfo /> — the same panel the library browser shows in its sidebar, so the two never drift apart. Accepts every <Dialog /> prop except children, plus:
| Prop | Type | Default | Description |
|---|---|---|---|
trigger | React.ReactElement | null | default icon button | The element that opens the dialog. null renders no trigger, for driving it with open/onOpenChange. |
Presentation mode and Open PDF file…#
Two items work with no document loaded at all — presentation mode belongs to the viewer, and opening a file has to work before anything is open, which is the one moment it matters most. Both are enabled as soon as their plugin is ready.
Everything else is document-scoped. embedpdf's document-scoped hooks throw when handed a document with no plugin state yet, so those items mount separately and swap for a disabled set until a document resolves — the same split every control in PDF Toolbar uses, applied to part of a menu rather than a whole component.
Scroll direction#
embedpdf exposes a setter for the scroll strategy but no reactive getter, so the radio group tracks the last selection made here rather than reading the engine back. Setting the strategy elsewhere won't move the mark. The plugin defines two strategies — vertical and horizontal — so there are no PDF.js-style wrapped or single-page modes to offer.