---
title: "Loading states, errors, and password prompts in react-pdf"
canonical_url: "https://www.nutrient.io/blog/react-pdf-loading-states-errors-passwords/"
md_url: "https://www.nutrient.io/blog/react-pdf-loading-states-errors-passwords.md"
last_updated: "2026-08-21T09:52:27.953Z"
description: "Manage document and page loading states, display error messages, track download progress, and handle password-protected PDFs in react-pdf."
---

**TL;DR**

- Both `<Document>` and `<Page>` accept `loading`, `error`, and `noData` props — each takes a string, a React element, or a render function.

- Track download progress with `onLoadProgress({ loaded, total })`. Be ready for `total === 0` when the server omits `Content-Length`.

- The document lifecycle is `onSourceSuccess` → `onLoadProgress` → `onLoadSuccess`; the page lifecycle adds text-layer, annotation, and render callbacks.

- For password-protected files, implement `onPassword(callback, reason)` and inspect `PasswordResponses.NEED_PASSWORD`/`INCORRECT_PASSWORD`. Call `callback(null)` to abort if the user cancels.

`react-pdf` provides built-in props for every loading state — document loading, page loading, errors, and password prompts. This guide covers all of them.

## Document loading states

The `Document` component has three display-state props:

```tsx

<Document
  file={file}
  loading={<Spinner />}
  error={<ErrorMessage />}
  noData={<EmptyState />}

>

  <Page pageNumber={1} />
</Document>

```

| Prop      | When shown                             | Default                      |
| --------- | -------------------------------------- | ---------------------------- |
| `loading` | While the PDF is being fetched/parsed  | `"Loading PDF..."`           |
| `error`   | When loading fails                     | `"Failed to load PDF file."` |
| `noData`  | When the `file` prop is null/undefined | `"No PDF file specified."`   |

Each accepts a **string**, **React element**, or **function**:

```tsx

// String.
<Document loading="Please wait..." />

// React element.
<Document loading={<div className="spinner"><Spinner /></div>} />

// Function (render function).
<Document loading={() => <CustomLoader />} />

```

## Page loading states

`Page` has the same three props, independently from `Document`:

```tsx

<Document file={file}>
  <Page
    pageNumber={1}
    loading={<PageSkeleton />}
    error={<PageError />}
    noData={<NoPageSelected />}
  />
</Document>

```

This means you can show a document-level spinner while the PDF downloads, then page-level skeletons while individual pages render.

## Loading progress

Track download progress with `onLoadProgress`:

```tsx

function PDFWithProgress() {
  const [progress, setProgress] = useState(0);
  const [loaded, setLoaded] = useState(false);

  return (
    <Document
      file={file}
      onLoadProgress={({ loaded, total }) => {
        if (total > 0) {
          setProgress(Math.round((loaded / total) * 100));
        }
      }}
      onLoadSuccess={() => setLoaded(true)}
      loading={
        <div>
          <progress value={progress} max={100} />
          <span>{progress}%</span>
        </div>
      }
    >
      <Page pageNumber={1} />
    </Document>
  );
}

```

`onLoadProgress` may be called multiple times during download. `total` can be `0` if the server doesn’t send `Content-Length`.

## Document callbacks

```tsx

<Document
  file={file}
  onSourceSuccess={() => {
    // File source resolved (URL fetched, File read, etc.).
  }}
  onSourceError={(error) => {
    // Failed to resolve file source.
    console.error("Source error:", error);
  }}
  onLoadSuccess={(pdf) => {
    // PDF parsed successfully.
    console.log("Pages:", pdf.numPages);
  }}
  onLoadError={(error) => {
    // Failed to parse PDF.
    console.error("Load error:", error);
  }}

>

  <Page pageNumber={1} />
</Document>

```

The loading lifecycle is:

1. `onSourceSuccess`/`onSourceError` — Resolving the `file` prop to loadable data

2. `onLoadProgress` — Download progress (may fire multiple times)

3. `onLoadSuccess`/`onLoadError` — PDF parsing complete

## Page callbacks

`Page` has its own set of lifecycle callbacks, independent from `Document`:

```tsx

<Page
  pageNumber={1}
  onLoadSuccess={(page) => {
    console.log("Page loaded:", page.pageNumber);
  }}
  onLoadError={(error) => {
    console.error("Page load error:", error);
  }}
  onRenderSuccess={() => {
    console.log("Canvas rendered");
  }}
  onRenderError={(error) => {
    console.error("Render error:", error);
  }}
/>

```

Page rendering lifecycle:

1. `onLoadSuccess`/`onLoadError` — Page data loaded

2. `onGetTextSuccess`/`onGetTextError` — Text layer data extracted

3. `onGetAnnotationsSuccess`/`onGetAnnotationsError` — Annotations loaded

4. `onRenderSuccess`/`onRenderError` — Canvas rendering complete

5. `onRenderTextLayerSuccess`/`onRenderTextLayerError` — Text layer rendered

6. `onRenderAnnotationLayerSuccess`/`onRenderAnnotationLayerError` — Annotation layer rendered

## Password-protected PDFs

`react-pdf` handles password-protected PDFs via the `onPassword` callback:

```tsx

import { PasswordResponses } from "react-pdf";

function ProtectedPDF() {
  const [file, setFile] = useState(null);

  const handlePassword = (callback, reason) => {
    if (reason === PasswordResponses.NEED_PASSWORD) {
      const password = prompt("This PDF is password-protected. Enter password:");
      callback(password);
    } else if (reason === PasswordResponses.INCORRECT_PASSWORD) {
      const password = prompt("Incorrect password. Try again:");
      callback(password);
    }
  };

  return (
    <Document file={file} onPassword={handlePassword}>
      <Page pageNumber={1} />
    </Document>
  );
}

```

### Custom password dialog

For full control over the prompt’s appearance, store the callback and render your own dialog:

```tsx

function ProtectedPDF() {
  const [passwordNeeded, setPasswordNeeded] = useState(false);
  const [password, setPassword] = useState("");
  const callbackRef = useRef(null);

  const handlePassword = (callback, reason) => {
    callbackRef.current = callback;
    setPasswordNeeded(true);
  };

  const submitPassword = () => {
    if (callbackRef.current) {
      callbackRef.current(password);
      setPasswordNeeded(false);
      setPassword("");
    }
  };

  // If the user cancels, call `callback(null)` to abort the loading task —
  // otherwise it hangs waiting for a password forever.
  const cancelPassword = () => {
    callbackRef.current?.(null);
    setPasswordNeeded(false);
    setPassword("");
  };

  return (
    <>
      <Document file={file} onPassword={handlePassword}>
        <Page pageNumber={1} />
      </Document>

      {passwordNeeded && (
        <dialog open>
          <h3>Password Required</h3>
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            onKeyDown={(e) => e.key === "Enter" && submitPassword()}
          />
          <button onClick={submitPassword}>Submit</button>
          <button onClick={cancelPassword}>Cancel</button>
        </dialog>
      )}
    </>
  );
}

```

### PasswordResponses

The `reason` argument passed to `onPassword` is one of two `PasswordResponses` values:

```tsx

import { PasswordResponses } from "react-pdf";

PasswordResponses.NEED_PASSWORD;      // 1 — first attempt.
PasswordResponses.INCORRECT_PASSWORD;  // 2 — wrong password, try again.

```

If you don’t provide `onPassword`, `react-pdf` falls back to `window.prompt`.

## Key points

- Both `Document` and `Page` have independent `loading`, `error`, and `noData` props.

- Each accepts a string, React element, or render function.

- `onLoadProgress` gives download progress but `total` may be 0.

- Password handling uses a callback pattern — store the callback ref and call it when ready.

- The `PasswordResponses` constant tells you whether it’s a first attempt or a retry.

- Default behavior without `onPassword` uses `window.prompt`.

## How Nutrient Web SDK handles this

All the per-component loading props, error handling callbacks, and custom password dialogs shown above are built into Nutrient Web SDK:

```js

// Loading states, errors, and password dialogs are built in.
const instance = await NutrientViewer.load({
  container: "#pdf-container",

  document: "document.pdf",
  // Built-in loading spinner, error messages, and password prompt.
  // No `loading`/`error`/`noData` props needed.
});

```

No per-component `loading`/`error`/`noData` props, no custom password dialog, no `onLoadProgress` tracking. Nutrient provides polished, accessible loading states, error messages, and password prompts out of the box — matching your app’s theme automatically.

[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

#### Can I show different spinners for the document load and individual page renders?

Yes. `<Document>` and `<Page>` each have their own `loading`, `error`, and `noData` props. A common pattern is a fullscreen spinner on `<Document loading>` while the PDF downloads, then per-page skeletons on `<Page loading>` while each page renders to canvas.

#### Why is <code>total</code> zero in <code>onLoadProgress</code>?

PDF.js reports `total` from the HTTP `Content-Length` header. If the server doesn’t send one — common with chunked transfer encoding, some proxies, or `Content-Encoding: gzip` responses — `total` stays `0`. Guard your percentage math with `if (total > 0)` and fall back to an indeterminate spinner.

#### What’s the difference between <code>onSourceSuccess</code> and <code>onLoadSuccess</code>?

`onSourceSuccess` fires when the `file` prop has been resolved to loadable data (URL fetched, `File`/`Blob` read, etc.). `onLoadSuccess` fires later, after PDF.js finishes parsing the document and exposes `numPages` and the page-fetching API.

#### What happens if I don’t pass <code>onPassword</code>?

`react-pdf` falls back to `window.prompt` with default English messages (“Enter the password to open this PDF file.”/“Invalid password. Please try again.”). It works but it’s not customizable, not styleable, and not localized — provide `onPassword` for anything user-facing.

#### How do I cancel out of the password prompt cleanly?

Call the `callback` with `null` (or any falsy value). PDF.js treats that as a cancellation and rejects the loading task — `onLoadError` will fire with a `PasswordException`. If you just close the dialog without invoking the callback, the loading task stays pending forever.

#### Why does my error component never show even when the PDF is broken?

Two common reasons: (1) the error happened during *source* resolution, not document loading — wire up `onSourceError` separately, and (2) you used a render function that returns `null` for some error types. Make sure your `error` render path is hit by logging inside `onLoadError` first.
---

## 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)
- [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)
- [Auto Tagging And Document Accessibility In Dotnet Sdk](/blog/auto-tagging-and-document-accessibility-in-dotnet-sdk.md)
- [Best Document Ai Platforms](/blog/best-document-ai-platforms.md)
- [Best Document Viewers](/blog/best-document-viewers.md)
- [Build Vs Buy Document Extraction](/blog/build-vs-buy-document-extraction.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)
- [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 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)
- [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 Pdf Editors](/blog/javascript-pdf-editors.md)
- [Javascript Pdf Libraries](/blog/javascript-pdf-libraries.md)
- [Linearized Pdf](/blog/linearized-pdf.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 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)
- [Using Yarn](/blog/react-pdf-editor.md)
- [React Pdf Setup Basic Rendering](/blog/react-pdf-setup-basic-rendering.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)
- [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)

