react-native-pdf

A cross-platform PDF viewer component for React Native, with zoom, paging, password protection, and native text selection.

Library
npm
v7.0.5
1,810stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
79/100Good
Development Activity68
Maintenance76
Community72
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
68/100Good
Architecture72
Code Quality55
Innovation68
Learning Curve75

react-native-pdf is a <Pdf /> component that renders PDF documents inside a React Native app on iOS, Android, and Windows. It loads a PDF from a URL, local file path, bundled asset, base64 string, blob, or content URI, optionally caching the downloaded file, and hands off the actual decoding and rendering to native PDF engines on each platform rather than reimplementing a renderer in JavaScript.

On Android it renders through io.legere:pdfiumandroid (a Pdfium binding), and on iOS it renders through Apple’s native PDFKit framework, with a legacy non-PDFKit fallback path retained for older setups. A Windows implementation (RCTPdf) covers RN Windows apps. The component supports both the legacy view-manager architecture and React Native’s new Fabric architecture via a codegen’d native component, so it works across old and new arch React Native apps.

Beyond basic rendering, it exposes pinch-to-zoom and double-tap-to-zoom gestures, horizontal or vertical paging, a setPage() imperative method, password-protected PDF support, and native text selection with a onTextSelectionChange callback (iOS, via PDFKit). It is widely used as the default choice for in-app PDF viewing in React Native apps that need to display invoices, contracts, reports, or downloaded documents without shelling out to an external viewer or a WebView-based PDF.js renderer.

What You Get

  • A <Pdf source={...} /> component supporting URL, local file, asset, base64, blob, and content-URI sources, with optional on-disk caching and expiration
  • Pinch-to-zoom, double-tap-to-zoom, horizontal/vertical paging, and a single-page thumbnail mode
  • Password-protected PDF support with an onError callback surfacing incorrect-password failures
  • Native text selection on iOS via PDFKit, exposed through enableTextSelection and onTextSelectionChange
  • An imperative setPage(pageNumber) ref method plus onLoadComplete, onPageChanged, onScaleChanged, and onPressLink callbacks
  • Support for both the legacy React Native architecture and the new Fabric architecture via a codegen’d native component

Common Use Cases

  • Viewing downloaded invoices, receipts, or reports inside a mobile app without leaving the app or opening a system PDF viewer
  • Displaying contracts or legal documents that require password protection and page-by-page navigation
  • Building an in-app document reader with pinch-zoom and page-jump controls for catalogs, manuals, or e-books
  • Rendering PDFs bundled as app assets (e.g. onboarding guides, terms of service) via bundle-assets:// sources
  • Previewing files fetched over HTTP(S) with progress reporting via onLoadProgress before the user views them

Under The Hood

Architecture The library is split between a cross-platform JS façade (Pdf in index.js) and per-platform native renderers. Pdf resolves the source prop into a local file path — downloading, decoding base64, or copying an asset via react-native-blob-util as needed — then hands that resolved path down to a native view: on iOS/Android it renders the codegen’d Fabric component from fabric/RNPDFPdfNativeComponent.js (falling back to the old-arch view manager when Fabric isn’t enabled), and on Windows it renders a requireNativeComponent('RCTPdf', ...) view. A separate legacy path (PdfView.js, PdfPageView.js, PdfManager.js) implements a page-by-page virtualized FlatList renderer with its own DoubleTapView/PinchZoomView gesture wrappers, used only when Fabric is unavailable and PDFKit is disabled; this dual-path structure (native single-view renderer vs. JS-orchestrated per-page virtualization) is the main architectural complexity, and native events (page loaded, page changed, text selected, link pressed) are marshaled back to JS as a single pipe-delimited onChange string that the JS layer parses by message type.

Tech Stack The JS layer is plain React (class components, no hooks) targeting react-native ”*” as a peer dependency, using deprecated-react-native-prop-types and prop-types for prop validation, crypto-js’s SHA1 for cache-file naming, and react-native-blob-util (a required peer dependency) for all filesystem and network I/O. Native code is genuinely three separate implementations: Android (Java, Gradle, io.legere:pdfiumandroid for PDF decoding, AGP 7.4.2), iOS (Objective-C++, CocoaPods, Apple’s PDFKit framework with a RCT_NEW_ARCH_ENABLED conditional podspec for Fabric vs. legacy builds), and Windows (a separate windows/RCTPdf native module for React Native Windows). Fabric codegen types are declared in Flow (fabric/RNPDFPdfNativeComponent.js).

Code Quality There are no unit or component tests for the library itself — the only test file in the repository (FabricExample/__tests__/App.test.tsx) exercises the example app, and CI (.github/workflows/windows-ci.yml) only runs an Appium-driven Windows build/smoke test, not JS-level assertions. Error handling is mixed: newer async paths (file download, unlink-then-copy sequencing) use explicit await/try...catch with dedicated error constructors (_createDownloadError), evident in recent changelog entries fixing unhandled promise rejections and ENOENT races, while older code paths still rely on bare .then()/.catch() chains. Naming is consistent (_ prefix for private methods, prop names mirrored across JS/native), and TypeScript consumers get types via a hand-maintained index.d.ts rather than being derived from the JS source.

What Makes It Unique Rather than parsing and rendering PDF content in JavaScript (as WebView/PDF.js-based approaches do), it defers entirely to each platform’s native PDF engine — Pdfium on Android, PDFKit on iOS — giving it native rendering performance and, on iOS, native text selection for free from PDFKit rather than a custom-built selection layer. Maintaining working legacy and Fabric render paths simultaneously, across three native platforms (iOS, Android, Windows) in the same package, is a maintenance burden most comparable RN libraries don’t take on.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search