This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /blog/react-pdf-annotation-layer-forms.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. react-pdf annotation layer: Links, forms, and filtering

Table of contents

    A guide to the 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.
    react-pdf annotation layer: Links, forms, and filtering
    TL;DR
    • Import react-pdf/dist/Page/AnnotationLayer.css and 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 filterAnnotations to show or hide specific subtypes, and use onGetAnnotationsSuccess to inspect raw annotation data.
    • react-pdf doesn’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 typeRendered as
    LinkClickable <a> tag
    Text (popup note)Note icon with expandable popup
    HighlightColored overlay
    FreeTextPositioned text element
    Widget (form field)<input>, <select>, or <textarea>
    FileAttachmentDownload icon

    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>
    PropDefaultDescription
    externalLinkTargetBrowser 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 fieldHTML 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.css for proper annotation styling.
    • renderAnnotationLayer is true by default.
    • renderForms={true} makes form fields interactive (requires renderAnnotationLayer).
    • filterAnnotations lets you selectively show/hide annotation types.
    • Use externalLinkTarget="_blank" to open PDF links in new tabs.
    • onGetAnnotationsSuccess gives 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

    Is the 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.

    Why aren’t my PDF form fields interactive?

    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.

    Can I save the values a user typed into a PDF form?

    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.

    How do I hide certain annotation types?

    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.

    How do I open PDF links in a new tab?

    Set externalLinkTarget="_blank" on <Document>. externalLinkRel defaults to "noopener noreferrer nofollow" for safety; override it if you need a different rel policy.

    Can I style annotations with my own CSS?

    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.

    Austin Nguyen

    Austin Nguyen

    AI Engineer

    When Austin isn’t pulling all-nighters to build new features, he enjoys watching science videos on YouTube and cooking.

    Explore related topics

    Try for free Ready to get started?