react-pdf annotation layer: Links, forms, and filtering
Table of contents
react-pdf annotation layer — rendering clickable links, interactive form fields, and popup notes from PDFs, plus how to filter annotations by type and style them with CSS.
- Import
react-pdf/dist/Page/AnnotationLayer.cssand the annotation layer renders by default — links, popup notes, highlights, and widgets become real DOM elements over the canvas. - Set
renderForms={true}on<Page>to turn PDF form fields into interactive<input>/<select>/<textarea>elements (AcroForm only — no XFA). - Use
filterAnnotationsto show or hide specific subtypes, and useonGetAnnotationsSuccessto inspect raw annotation data. react-pdfdoesn’t expose APIs for creating/editing annotations or saving filled form values back to the PDF — for that, use an SDK like Nutrient Web SDK.
The annotation layer renders elements that exist within the PDF file itself — links, form fields, popups, and other interactive elements. react-pdf renders these as HTML elements overlaid on the canvas.
Enabling the annotation layer
The annotation layer is enabled by default. Import the CSS:
import "react-pdf/dist/Page/AnnotationLayer.css";<Page pageNumber={1} renderAnnotationLayer={true} /> {/* Default. */}Disable it:
<Page pageNumber={1} renderAnnotationLayer={false} />What the annotation layer renders
| PDF annotation type | Rendered as |
|---|---|
Link | Clickable <a> tag |
Text (popup note) | Note icon with expandable popup |
Highlight | Colored overlay |
FreeText | Positioned text element |
Widget (form field) | <input>, <select>, or <textarea> |
FileAttachment | Download icon |
External link control
Control how links to external URLs behave:
<Document file={file} externalLinkTarget="_blank" // Open in new tab. externalLinkRel="noopener noreferrer nofollow" // Default value.> <Page pageNumber={1} /></Document>| Prop | Default | Description |
|---|---|---|
externalLinkTarget | Browser default | "_self", "_blank", "_parent", "_top" |
externalLinkRel | "noopener noreferrer nofollow" | rel attribute for security |
Interactive forms
Enable form interactivity with renderForms:
<Page pageNumber={1} renderAnnotationLayer={true} // Required for forms. renderForms={true}/>This renders PDF form fields as interactive HTML elements:
| PDF form field | HTML element |
|---|---|
| Text field | <input type="text"> |
| Text area | <textarea> |
| Checkbox | <input type="checkbox"> |
| Radio button | <input type="radio"> |
| Dropdown | <select> |
| List box | <select multiple> |
| Push button | <button> |
Example: PDF form viewer
The component below puts the two props together to render an interactive form:
function FormViewer() { return ( <Document file="form.pdf"> <Page pageNumber={1} renderAnnotationLayer={true} renderForms={true} /> </Document> );}Users can fill in the form fields directly in the browser. Note that react-pdf supports AcroForm fields only — dynamic XFA forms (common in government and banking PDFs) aren’t rendered as interactive widgets. There’s also no built-in API to save filled values back to the PDF; you’d need a library like pdf-lib to write the values into a new file.
Filtering annotations
Use filterAnnotations to control which annotations are rendered:
<Page pageNumber={1} filterAnnotations={({ annotations }) => { // Only show links, hide everything else. return annotations.filter((annot) => annot.subtype === "Link"); }}/>Common filter use cases
The filterAnnotations callback receives the full annotation array on every render, so any subtype comparison you write works as a filter:
// Hide all popup notes.filterAnnotations={({ annotations }) => annotations.filter((a) => a.subtype !== "Text")}
// Hide form fields.filterAnnotations={({ annotations }) => annotations.filter((a) => a.subtype !== "Widget")}
// Only show specific annotation types.filterAnnotations={({ annotations }) => annotations.filter((a) => ["Link", "Highlight"].includes(a.subtype))}Annotation callbacks
react-pdf exposes separate callbacks for reading raw annotation data (onGetAnnotationsSuccess/onGetAnnotationsError) and for the annotation layer finishing its render (onRenderAnnotationLayerSuccess/onRenderAnnotationLayerError):
<Page pageNumber={1} onGetAnnotationsSuccess={(annotations) => { // Array of annotation objects from the PDF. annotations.forEach((annot) => { console.log(annot.subtype); // "Link", "Text", "Widget", etc. console.log(annot.rect); // [x1, y1, x2, y2]. console.log(annot.url); // External URL (for links). console.log(annot.fieldName); // Form field name (for widgets). console.log(annot.fieldValue); // Form field value. }); }} onGetAnnotationsError={(error) => { console.error("Failed to load annotations:", error); }} onRenderAnnotationLayerSuccess={() => { console.log("Annotation layer rendered"); }} onRenderAnnotationLayerError={(error) => { console.error("Failed to render annotations:", error); }}/>Image resources path
Some annotations reference external images (like stamp icons). Set the path prefix:
<Document file={file} imageResourcesPath="/images/" // Prefix for annotation SVG src.> <Page pageNumber={1} /></Document>Or set per page:
<Page pageNumber={1} imageResourcesPath="/images/" />Styling annotations
Customize annotation appearance via CSS:
/* Style link annotations. */.react-pdf__Page__annotations .linkAnnotation a { border: none;}
.react-pdf__Page__annotations .linkAnnotation a:hover { background-color: rgba(255, 255, 0, 0.2);}
/* Style form inputs. */.react-pdf__Page__annotations .textWidgetAnnotation input { font-size: 12px; border: 1px solid #ccc; padding: 2px;}
/* Style checkboxes. */.react-pdf__Page__annotations .buttonWidgetAnnotation.checkBox input { accent-color: #4A90D9;}Key points
- Import
react-pdf/dist/Page/AnnotationLayer.cssfor proper annotation styling. renderAnnotationLayeristrueby default.renderForms={true}makes form fields interactive (requiresrenderAnnotationLayer).filterAnnotationslets you selectively show/hide annotation types.- Use
externalLinkTarget="_blank"to open PDF links in new tabs. onGetAnnotationsSuccessgives you raw annotation data for custom processing.- PDF form fields become standard HTML inputs — you can style them with CSS.
How Nutrient Web SDK handles this
react-pdf renders annotations read-only and lets users type into AcroForm fields, but it doesn’t expose APIs to create/edit/delete annotations or to save filled form values back to the PDF. Nutrient Web SDK covers both:
// Annotations — create, edit, delete (not just read-only).const annotation = new NutrientViewer.Annotations.HighlightAnnotation({ pageIndex: 0, rects: NutrientViewer.Immutable.List([ new NutrientViewer.Geometry.Rect({ left: 50, top: 100, width: 200, height: 20 }), ]),});await instance.create(annotation);
// Forms — read and write values programmatically.await instance.setFormFieldValues({ "Name": "Jane Doe" });Nutrient supports creating, editing, and deleting 17+ annotation types, plus interactive forms with validation, calculation fields, and digital signatures — and the filled or annotated document can be exported as a flattened PDF.
Learn more about Nutrient Web SDK | Migration guide | Contact Sales
FAQ
react-pdf annotation layer enabled by default?Yes — renderAnnotationLayer defaults to true. You only need to import the matching stylesheet (react-pdf/dist/Page/AnnotationLayer.css) for elements to position correctly over the canvas.
The annotation layer renders forms as static visuals unless you opt in. Set renderForms={true} on <Page> (and keep renderAnnotationLayer={true}). This works for AcroForm fields only — dynamic XFA forms aren’t supported by PDF.js, which react-pdf wraps.
Not with react-pdf alone. The library renders form fields as HTML inputs but doesn’t write changes back to the PDF. To persist values, read them from the DOM (or from onGetAnnotationsSuccess plus your own state) and use a library like pdf-lib to update the file, or switch to an SDK that writes form values back to the file natively.
Use filterAnnotations to return only the subtypes you want. For example, annotations.filter((a) => a.subtype !== "Widget") hides form fields, and ["Link", "Highlight"].includes(a.subtype) keeps only links and highlights.
Set externalLinkTarget="_blank" on <Document>. externalLinkRel defaults to "noopener noreferrer nofollow" for safety; override it if you need a different rel policy.
Yes. The annotation layer uses stable public class names — .linkAnnotation, .textWidgetAnnotation, .buttonWidgetAnnotation, etc., all scoped under .react-pdf__Page__annotations. Override styles after importing AnnotationLayer.css so your rules win the cascade.