Every PDF carries a set of permission flags — whether it may be printed, copied, annotated, or edited. embedpdf reads those flags on open and enforces them at the source: the print plugin refuses to print a document that forbids it, the selection plugin refuses to copy, and so on.
What the plugins don't do is tell the user. A button wired to a forbidden action still looks clickable, and clicking it does nothing. pdfviewcn's chrome closes that gap — a control whose action the document forbids renders disabled, with a tooltip that says why.
Permission flags are the document's stated intent, not a security boundary. They live in the file and are enforced in the browser, so anyone with the bytes can lift them. Treat them as "respect the author's wishes," not "keep the content safe."
What reflects the flags#
These controls read the active document's effective permissions and disable themselves when the matching flag is denied. Each is a standalone component, so this works whether you install them individually or through the viewer block.
| Control | Requires permission | Name in overrides |
|---|---|---|
PdfPrintButton | print | |
PdfCaptureButton | Copy contents | copyContents |
PdfAnnotationToolbar | Modify annotations | modifyAnnotations |
PdfRedactionToolbar | Modify contents | modifyContents |
PdfRedactionBar | Modify contents (to apply) | modifyContents |
PdfRedactionPanel | Modify contents (to remove a mark) | modifyContents |
PdfFormFieldInspector | Modify annotations, or fill forms | modifyAnnotations, fillForms |
The last three disable part of themselves rather than all of it. The redaction bar and panel stay mounted and readable when editing is denied — marks still exist and still need reporting; it's only applying and removing that are refused. The form field inspector splits by section, because a form that's fillable but not editable is the common case for one somebody sends you.
There's nothing to wire up. Here's the print button against a document whose print flag is denied — disabled, with a tooltip on hover. Download sits beside it untouched, since nothing gates it:
"use client";
import { PdfToolbar } from "@/components/pdf-toolbar";Each control's own page carries the same demo for its flag: copying, annotating, and editing.
Overriding a document's flags#
Permissions resolve in layers: a per-document override wins over the PDF's own flags. Pass a permissions config alongside a document to force a flag on or off, regardless of what the file says.
<PdfViewer
documents={[
{
url: "/sample.pdf",
permissions: {
// true = force allow, false = force deny.
overrides: { print: false, copyContents: false },
},
},
]}
className="h-[720px]"
>
<PdfViewerContent />
</PdfViewer>Use false to deny an action the PDF otherwise allows — a viewer that never prints, say. Use true to grant one the PDF withholds, when your app is the authority on access.
An override left undefined falls through to the PDF's flag, so you only list the ones you mean to change.
Ignoring the PDF's flags entirely#
To start from "everything allowed" and layer overrides on top — rather than starting from what the file declares — set enforceDocumentPermissions to false:
permissions: {
// Ignore the PDF's flags; treat every action as allowed…
enforceDocumentPermissions: false,
// …except the ones you deny here.
overrides: { print: false },
}This is the escape hatch for documents whose flags are wrong or missing, when your own backend already decides who may do what.
Where the model comes from#
The flags, the layered resolution, and the plugin-level enforcement are embedpdf's, documented under Security. pdfviewcn adds the chrome that tells the user which actions the document has taken off the table.