---
title: "Custom rendering modes and context hooks in react-pdf"
canonical_url: "https://www.nutrient.io/blog/react-pdf-custom-rendering-hooks/"
md_url: "https://www.nutrient.io/blog/react-pdf-custom-rendering-hooks.md"
last_updated: "2026-09-04T17:08:46.129Z"
description: "Use react-pdf render modes for custom page output, access PDF state with context hooks, and work with structure tree data and ref forwarding."
---

**TL;DR**

- `renderMode` on `<Page>` switches between `"canvas"` (default), `"custom"` (with a `customRenderer`), and `"none"` (skips canvas paint — useful for headless text extraction).

- `react-pdf` exports three context hooks — `useDocumentContext`, `usePageContext`, and `useOutlineContext` — for components nested inside `<Document>`, `<Page>`, or `<Outline>`.

- `inputRef` forwards a ref to the root `<div>`; `canvasRef` exposes the rendered `<canvas>` directly for things like exporting to a data URL.

- Structure tree data (semantic page content for accessibility) is available via `onGetStructTreeSuccess` after the page renders.

`react-pdf` supports custom rendering for cases where the default canvas output isn’t sufficient. It also exports context hooks for building custom child components.

## Render modes

The `renderMode` prop controls how a page is visually rendered:

| Mode       | Description                                           |
| ---------- | ----------------------------------------------------- |
| `"canvas"` | Default. Renders to an HTML `<canvas>` element        |
| `"custom"` | Uses your `customRenderer` component                  |
| `"none"`   | No visual rendering (useful for data extraction only) |

### Setting render mode

Per-page:

```tsx

<Page pageNumber={1} renderMode="custom" customRenderer={MyRenderer} />

```

Document-wide (applies to all `Page` and `Thumbnail` children):

```tsx

<Document file={file} renderMode="canvas">
  <Page pageNumber={1} />
</Document>

```

## Custom renderer

When `renderMode="custom"`, you must provide a `customRenderer` component:

```tsx

function MyCustomRenderer() {
  // Access page context for rendering data.
  const pageContext = usePageContext();

  return (
    <div className="custom-page">
      {/* Your custom rendering logic. */}
    </div>
  );
}

// In your component tree:
// <Page
//   pageNumber={1}
//   renderMode="custom"
//   customRenderer={MyCustomRenderer}
// />

```

## The none mode

Use `renderMode="none"` when you only want data, not visual output:

```tsx

// Extract text without rendering anything visible.
<Page
  pageNumber={1}
  renderMode="none"
  renderTextLayer={false}
  renderAnnotationLayer={false}
  onGetTextSuccess={({ items }) => {
    const fullText = items.map((item) => item.str).join(" ");
    processText(fullText);
  }}
/>

```

This saves memory and CPU by skipping canvas rendering entirely.

## Context hooks

`react-pdf` exports three hooks for building custom child components that need access to PDF state.

### useDocumentContext

Access document-level state from any child of `Document`:

```tsx

import { useDocumentContext } from "react-pdf";

function CustomComponent() {
  const documentContext = useDocumentContext();
  // Access the loaded PDF object, callbacks, options, etc.
  return <div>...</div>;
}

// Must be inside a `Document`:
// <Document file={file}>
//   <CustomComponent />
// </Document>

```

### usePageContext

Access page-level state from any child of `Page`:

```tsx

import { usePageContext } from "react-pdf";

function PageOverlay() {
  const pageContext = usePageContext();
  // Access page number, scale, rotation, viewport, etc.
  return <div className="overlay">...</div>;
}

// In your component tree:
// <Document file={file}>
//   <Page pageNumber={1}>
//     <PageOverlay />
//   </Page>
// </Document>

```

### useOutlineContext

Access outline state from children of `Outline`:

```tsx

import { useOutlineContext } from "react-pdf";

function CustomOutlineItem() {
  const outlineContext = useOutlineContext();
  return <div>...</div>;
}

// In your component tree:
// <Document file={file}>
//   <Outline>
//     <CustomOutlineItem />
//   </Outline>
// </Document>

```

## Structure tree callbacks

`react-pdf` exposes the PDF structure tree (accessibility data) via callbacks:

```tsx

<Page
  pageNumber={1}
  onGetStructTreeSuccess={(structTree) => {
    // Structure tree data for accessibility.
    console.log(structTree);
  }}
  onGetStructTreeError={(error) => {
    console.error("Failed to get struct tree:", error);
  }}
/>

```

The structure tree contains semantic information about the page content (headings, paragraphs, lists, etc.).

## Forwarding refs

`Document`, `Page`, `Outline`, and `Thumbnail` all support `inputRef` for forwarding a ref to their root `<div>`:

```tsx

function MeasuredPage() {
  const pageRef = useRef(null);

  return (
    <Page
      pageNumber={1}
      inputRef={pageRef}
      onRenderSuccess={() => {
        const { width, height } = pageRef.current.getBoundingClientRect();
        console.log(`Page rendered at ${width}x${height}`);
      }}
    />
  );
}

```

`Page` also supports `canvasRef` for direct canvas access:

```tsx

<Page
  pageNumber={1}
  canvasRef={(canvas) => {
    // Direct access to the rendered canvas element.
    if (canvas) {
      const dataUrl = canvas.toDataURL("image/jpeg");
      // Use the canvas image...
    }
  }}
/>

```

## Key points

- `renderMode` controls visual output: `"canvas"` (default), `"custom"`, or `"none"`.

- `"none"` mode is useful for text extraction without visual rendering.

- Context hooks (`useDocumentContext`, `usePageContext`, `useOutlineContext`) let you build custom child components.

- `inputRef` forwards to the root div, and `canvasRef` forwards to the canvas element.

- Structure tree data is available via `onGetStructTreeSuccess` for accessibility.

## How Nutrient Web SDK handles this

Instead of the render modes, context hooks, and ref forwarding patterns shown above, Nutrient Web SDK provides a straightforward custom renderer API:

```js

const instance = await NutrientViewer.load({
  container: "#pdf-container",

  document: "document.pdf",
  customRenderers: {
    Annotation: ({ annotation }) => {
      // Only customize note annotations; fall back to default UI for everything else.
      if (!(annotation instanceof NutrientViewer.Annotations.NoteAnnotation)) {
        return null;
      }
      const node = document.createElement("div");
      node.className = "custom-annotation";
      node.textContent = `📝 ${annotation.text?.value?? ""}`;
      return { node, append: false }; // append: false replaces the default appearance.
    },
  },
});

```

There are no render modes to toggle, no context hooks to learn, and no ref forwarding patterns to manage. The `Annotation` renderer fires for every annotation type, so `instanceof` checks keep your custom UI scoped — return `null` to fall back to defaults. `append: false` (the default) replaces the built-in appearance; `append: true` adds your node alongside it.

[Learn more about Nutrient Web SDK](https://www.nutrient.io/sdk/web-overview/) | [Migration guide](https://www.nutrient.io/guides/web/about/migration-guides/migrating-from-react-pdf.md) | [Contact Sales](https://www.nutrient.io/contact-sales/?=sdk)

## FAQ

#### When should I use <code>renderMode="custom"</code>?

Use it when the default canvas output doesn’t fit — for example, to render pages as SVG, render them as plain HTML for full text reflow, or show a placeholder for virtualized lists. For everything else, `"canvas"` is faster and simpler.

#### What’s the difference between <code>renderMode="none"</code> and skipping the page entirely?

`"none"` still loads the page data (so callbacks like `onGetTextSuccess` and `onGetAnnotationsSuccess` fire), but it skips the canvas paint. It’s the right pick for headless text or metadata extraction. Not rendering a `<Page>` at all means no `getPage()` call and no callbacks.

#### Are the context hooks documented in the <code>react-pdf</code> README?

No — `useDocumentContext`, `usePageContext`, and `useOutlineContext` are exported from `react-pdf` but only appear in the source (`packages/react-pdf/src/index.ts`). They’re stable enough to use, but the only documentation is the type signatures — there are no narrative guides.

#### When does <code>onGetStructTreeSuccess</code> fire relative to other callbacks?

It fires after the page renders. The rough order is `onLoadSuccess` (page object available) → `onRenderSuccess` (canvas painted) → `onGetTextSuccess`/`onGetAnnotationsSuccess`/`onGetStructTreeSuccess` (data callbacks resolve). Don’t rely on a strict order between the three data callbacks — they fire as their underlying promises settle.

#### What’s the difference between <code>inputRef</code> and <code>canvasRef</code>?

`inputRef` forwards to the root `<div>` that wraps the canvas, text layer, and annotation layer — use it for measuring or focus management. `canvasRef` exposes the rendered `<canvas>` element directly, which is what you want for `toDataURL()`, custom WebGL compositing, or pixel-level image processing.

#### Can I read PDF accessibility tags from the structure tree?

Yes — `onGetStructTreeSuccess` receives a `StructTreeNode` tree describing tagged content (headings, paragraphs, lists, figures). Walk the tree to build alt-text overlays, screen reader-friendly outlines, or DOM mirrors of the page semantics.
---

## Related pages

- [The business case for accessibility: Five ways it drives enterprise value](/blog/5-ways-accessibility-drives-enterprise-value.md)
- [Accessibility Untangled Why It Matters Guide](/blog/accessibility-untangled-why-it-matters-guide.md)
- [Advanced Techniques For React Native Ui Components](/blog/advanced-techniques-for-react-native-ui-components.md)
- [`vector_store` holds your indexed documents (see the multimodal RAG post](/blog/agentic-rag.md)
- [How to build an AI agent for contract redlining against a compliance playbook](/blog/ai-contract-redlining-compliance-playbook.md)
- [Ai Document Automation Extraction To Action](/blog/ai-document-automation-extraction-to-action.md)
- [Ai Legal Assistant Document Authoring](/blog/ai-legal-assistant-document-authoring.md)
- [Amazon Textract Alternatives](/blog/amazon-textract-alternatives.md)
- [Start (clears any prior buffer), navigate the document, then stop into a file.](/blog/android-faster-pdf-rendering.md)
- [Android Pdf Out Of Memory Handling](/blog/android-pdf-out-of-memory-handling.md)
- [Angular File Viewer Pdf Image Office Files](/blog/angular-file-viewer-pdf-image-office-files.md)
- [Approvals Matrix](/blog/approvals-matrix.md)
- [Auto Tagging And Document Accessibility In Dotnet Sdk](/blog/auto-tagging-and-document-accessibility-in-dotnet-sdk.md)
- [Simple PII redaction.](/blog/automated-pii-removal.md)
- [Best Ai Document Workflow Platforms](/blog/best-ai-document-workflow-platforms.md)
- [Best Document Ai Platforms](/blog/best-document-ai-platforms.md)
- [Best Document Classification Platforms](/blog/best-document-classification-platforms.md)
- [Best document parser for RAG: LlamaParse vs. Unstructured vs. Reducto vs. Nutrient](/blog/best-document-parser-llamaparse-unstructured-reducto.md)
- [Best Document Parsing Apis](/blog/best-document-parsing-apis.md)
- [Best Document Viewers](/blog/best-document-viewers.md)
- [Best Multilingual Ocr Software](/blog/best-multilingual-ocr-software.md)
- [Best Secure Document Collaboration Platforms](/blog/best-secure-document-collaboration-platforms.md)
- [Build Vs Buy Document Extraction](/blog/build-vs-buy-document-extraction.md)
- [Business Automation](/blog/business-automation.md)
- [The CEO’s AI playbook: Why decision architecture beats model selection](/blog/ceo-ai-playbook-decision-architecture.md)
- [1. Extract and chunk the PDF.](/blog/chat-with-pdf.md)
- [Complete Guide To Pdfjs](/blog/complete-guide-to-pdfjs.md)
- [Construction Document Data Extraction](/blog/construction-document-data-extraction.md)
- [Convert One Drive Files To Pdf In Sharepoint](/blog/convert-one-drive-files-to-pdf-in-sharepoint.md)
- [Create And Edit Pdfs In Flutter](/blog/create-and-edit-pdfs-in-flutter.md)
- [Create Pdfs With React](/blog/create-pdfs-with-react.md)
- [Creating A Document Scanner With Ocr In Python](/blog/creating-a-document-scanner-with-ocr-in-python.md)
- [Creating And Filling Pdf Forms Programmatically In Javascript](/blog/creating-and-filling-pdf-forms-programmatically-in-javascript.md)
- [The CTO’s AI playbook: Why accountability architecture beats orchestration](/blog/cto-ai-playbook-accountability-architecture.md)
- [Digital Signatures](/blog/digital-signatures.md)
- [Digital Workflow Automation](/blog/digital-workflow-automation.md)
- [Document Ai Vs Ocr](/blog/document-ai-vs-ocr.md)
- [Document Extraction Confidence Scores](/blog/document-extraction-confidence-scores.md)
- [Document Viewer](/blog/document-viewer.md)
- [Document Watermarking](/blog/document-watermarking.md)
- [Emerging threats: Your logging system may be an agentic threat vector](/blog/emerging-threats-your-logging-system.md)
- [Extend Alternatives](/blog/extend-alternatives.md)
- [Extract Patient Data On Premises](/blog/extract-patient-data-on-premises.md)
- [app.py](/blog/extract-text-from-pdf-using-python.md)
- [Fillable Pdf](/blog/fillable-pdf.md)
- [How To Add Digital Signature To Pdf Using React](/blog/how-to-add-digital-signature-to-pdf-using-react.md)
- [How To Build A Dotnet Maui Pdf Viewer](/blog/how-to-build-a-dotnet-maui-pdf-viewer.md)
- [How To Build A Flutter Pdf Viewer](/blog/how-to-build-a-flutter-pdf-viewer.md)
- [or](/blog/how-to-build-a-javascript-pdf-viewer-with-pdfjs.md)
- [How To Build A Javascript Pdf Viewer](/blog/how-to-build-a-javascript-pdf-viewer.md)
- [or](/blog/how-to-build-a-nextjs-pdf-viewer.md)
- [How To Build A Powerpoint Viewer Using Javascript](/blog/how-to-build-a-powerpoint-viewer-using-javascript.md)
- [Using Yarn](/blog/how-to-build-a-react-excel-viewer.md)
- [How To Build A React Native Pdf Viewer](/blog/how-to-build-a-react-native-pdf-viewer.md)
- [How To Build A React Powerpoint Viewer](/blog/how-to-build-a-react-powerpoint-viewer.md)
- [How To Build A Reactjs File Viewer](/blog/how-to-build-a-reactjs-file-viewer.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer-with-react-pdf.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer.md)
- [How To Build A Reactjs Viewer With Pdfjs](/blog/how-to-build-a-reactjs-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer With Pdfjs](/blog/how-to-build-a-vuejs-pdf-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer](/blog/how-to-build-a-vuejs-pdf-viewer.md)
- [How To Build An Android Pdf Viewer](/blog/how-to-build-an-android-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Ng2 Pdf Viewer](/blog/how-to-build-an-angular-pdf-viewer-with-ng2-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Pdfjs](/blog/how-to-build-an-angular-pdf-viewer-with-pdfjs.md)
- [How To Convert Docx To Pdf Using Javascript](/blog/how-to-convert-docx-to-pdf-using-javascript.md)
- [How To Convert Docx To Pdf Using Python](/blog/how-to-convert-docx-to-pdf-using-python.md)
- [How To Convert Html To Pdf Using Html2pdf](/blog/how-to-convert-html-to-pdf-using-html2pdf.md)
- [or](/blog/how-to-convert-html-to-pdf-using-react.md)
- [How To Convert Html To Pdf Using Wkhtmltopdf And Csharp](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-csharp.md)
- [or](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-python.md)
- [How To Convert Html To Pptx](/blog/how-to-convert-html-to-pptx.md)
- [Quarterly report](/blog/how-to-convert-pdf-to-markdown-using-python.md)
- [How To Convert Word To Pdf In Nodejs](/blog/how-to-convert-word-to-pdf-in-nodejs.md)
- [or](/blog/how-to-create-a-react-js-signature-pad.md)
- [How To Create Pdfs With React To Pdf](/blog/how-to-create-pdfs-with-react-to-pdf.md)
- [How To Edit Pdfs Using Ios Pdf Library](/blog/how-to-edit-pdfs-using-ios-pdf-library.md)
- [How To Embed A Pdf Viewer In Your Website](/blog/how-to-embed-a-pdf-viewer-in-your-website.md)
- [How To Extract Tables From Pdf And Images](/blog/how-to-extract-tables-from-pdf-and-images.md)
- [How To Generate Pdf From Html With Nodejs](/blog/how-to-generate-pdf-from-html-with-nodejs.md)
- [base_url tells WeasyPrint where to resolve relative asset paths](/blog/how-to-generate-pdf-reports-from-html-in-python.md)
- [How To Merge Pdfs Using Javascript](/blog/how-to-merge-pdfs-using-javascript.md)
- [How To Ocr Pdfs In Linux](/blog/how-to-ocr-pdfs-in-linux.md)
- [How To Print Pdf In Csharp](/blog/how-to-print-pdf-in-csharp.md)
- [How To Programmatically Create And Fill Pdf Form In Angular](/blog/how-to-programmatically-create-and-fill-pdf-form-in-angular.md)
- [Open an image.](/blog/how-to-use-tesseract-ocr-in-python.md)
- [From an HTML string.](/blog/html-in-pdf-format.md)
- [Html To Pdf In Javascript](/blog/html-to-pdf-in-javascript.md)
- [Javascript Document Editor](/blog/javascript-document-editor.md)
- [Javascript Pdf Editors](/blog/javascript-pdf-editors.md)
- [Javascript Pdf Libraries](/blog/javascript-pdf-libraries.md)
- [Langextract Vs Llamaindex Extraction Comparison](/blog/langextract-vs-llamaindex-extraction-comparison.md)
- [Linearized Pdf](/blog/linearized-pdf.md)
- [Llamaparse Alternatives](/blog/llamaparse-alternatives.md)
- [Low Code No Code Document Integrations](/blog/low-code-no-code-document-integrations.md)
- [or](/blog/merge-pdfs.md)
- [Swift Package Manager](/blog/mobile-pdf-sdk.md)
- [`elements` come from your document parser — each has a type and content.](/blog/multimodal-rag.md)
- [Nutrient Flutter 6 Bindings Api](/blog/nutrient-flutter-6-bindings-api.md)
- [Nutrient Flutter Bindings Architecture](/blog/nutrient-flutter-bindings-architecture.md)
- [Nutrient Vs Conga Composer](/blog/nutrient-vs-conga-composer.md)
- [Online Document Viewer](/blog/online-document-viewer.md)
- [Open Pdf In Your Web App](/blog/open-pdf-in-your-web-app.md)
- [Building WCAG 2.2, Section 508, and PDF/UA-compliant PDFs with an SDK](/blog/pdf-accessibility.md)
- [Extract data from PDF files: A developer guide to structured data from PDFs and scans](/blog/pdf-data-extraction-developer-guide.md)
- [Pdf Extraction Benchmark Opendataloader Bench](/blog/pdf-extraction-benchmark-opendataloader-bench.md)
- [Pdf Extraction Document Case Studies](/blog/pdf-extraction-document-case-studies.md)
- [Pdf Page Labels](/blog/pdf-page-labels.md)
- [Pdf Sdk Compliance Security Checklist](/blog/pdf-sdk-compliance-security-checklist.md)
- [Pdf Sdk Performance Benchmark](/blog/pdf-sdk-performance-benchmark.md)
- [Pdf Ua Compliance Guide](/blog/pdf-ua-compliance-guide.md)
- [Pdfjs Accessibility Structtree Printing](/blog/pdfjs-accessibility-structtree-printing.md)
- [Pdfjs Advanced Loading Streaming Workers](/blog/pdfjs-advanced-loading-streaming-workers.md)
- [Pdfjs Annotation Editor Layer](/blog/pdfjs-annotation-editor-layer.md)
- [Pdfjs Area Annotations Canvas Capture](/blog/pdfjs-area-annotations-canvas-capture.md)
- [Pdfjs Coordinate Systems Pdf To Screen](/blog/pdfjs-coordinate-systems-pdf-to-screen.md)
- [Pdfjs Document Outline Bookmarks Metadata](/blog/pdfjs-document-outline-bookmarks-metadata.md)
- [Pdfjs Eventbus Guide](/blog/pdfjs-eventbus-guide.md)
- [macOS](/blog/pdfjs-file-format-conversion-to-pdf.md)
- [macOS](/blog/pdfjs-generating-pdf-thumbnails-pdf2pic.md)
- [Pdfjs Limitations Commercial Upgrade](/blog/pdfjs-limitations-commercial-upgrade.md)
- [Pdfjs Native Annotation Layer Forms](/blog/pdfjs-native-annotation-layer-forms.md)
- [Pdfjs Navigation Zoom Rotation](/blog/pdfjs-navigation-zoom-rotation.md)
- [Pdfjs Pdf Page Manipulation Pdf Lib](/blog/pdfjs-pdf-page-manipulation-pdf-lib.md)
- [Pdfjs React Viewer Setup](/blog/pdfjs-react-viewer-setup.md)
- [Pdfjs Rendering Overlays React Portals](/blog/pdfjs-rendering-overlays-react-portals.md)
- [Pdfjs Server Side Text Extraction](/blog/pdfjs-server-side-text-extraction.md)
- [Pdfjs Sticky Note Annotations](/blog/pdfjs-sticky-note-annotations.md)
- [Pdfjs Text Highlight Annotations](/blog/pdfjs-text-highlight-annotations.md)
- [Pdfjs Text Search Pdffindcontroller](/blog/pdfjs-text-search-pdffindcontroller.md)
- [Pdfjs Thumbnail Sidebar](/blog/pdfjs-thumbnail-sidebar.md)
- [Process Flows](/blog/process-flows.md)
- [React Native Pdf Annotation](/blog/react-native-pdf-annotation.md)
- [React Pdf Annotation Layer Forms](/blog/react-pdf-annotation-layer-forms.md)
- [Using Yarn](/blog/react-pdf-editor.md)
- [React Pdf Loading States Errors Passwords](/blog/react-pdf-loading-states-errors-passwords.md)
- [React Pdf Setup Basic Rendering](/blog/react-pdf-setup-basic-rendering.md)
- [React Pdf Text Layer Custom Renderer](/blog/react-pdf-text-layer-custom-renderer.md)
- [React Pdf Thumbnails Page Navigation](/blog/react-pdf-thumbnails-page-navigation.md)
- [Reducto Alternatives](/blog/reducto-alternatives.md)
- [Requisition System](/blog/requisition-system.md)
- [labels.py](/blog/route-documents-automatically-classify-api.md)
- [or](/blog/sample-blog-updated.md)
- [Sdk Product Updates Q2 2026](/blog/sdk-product-updates-q2-2026.md)
- [Add DWS MCP Server to your Claude Code project.](/blog/teaching-llms-to-read-pdfs.md)
- [Open an image file.](/blog/tesseract-python-guide.md)
- [The Six Best Pdf Generator Apis](/blog/the-six-best-pdf-generator-apis.md)
- [Define the HTML part of the document.](/blog/top-10-ways-to-generate-pdfs-in-python.md)
- [Top 5 Javascript Pdf Viewers](/blog/top-5-javascript-pdf-viewers.md)
- [or](/blog/top-js-pdf-libraries.md)
- [Convert an HTML file to PDF.](/blog/top-ten-ways-to-convert-html-to-pdf.md)
- [Vector Pdf](/blog/vector-pdf.md)
- [Wcag2 Accessibility Requirements Documents](/blog/wcag2-accessibility-requirements-documents.md)
- [Web Sdk Is Now Headless](/blog/web-sdk-is-now-headless.md)
- [What Are Annotations](/blog/what-are-annotations.md)
- [What Is A Vpat](/blog/what-is-a-vpat.md)
- [What Is Document Processing](/blog/what-is-document-processing.md)
- [What Is Intelligent Document Processing](/blog/what-is-intelligent-document-processing.md)
- [What Is Pdf Ua](/blog/what-is-pdf-ua.md)
- [Why Pdfium Is A Trusted Platform For Pdf Rendering](/blog/why-pdfium-is-a-trusted-platform-for-pdf-rendering.md)
- [Why Your Ai Agent Hallucinates Pdf Table Data](/blog/why-your-ai-agent-hallucinates-pdf-table-data.md)

