Somebody uploads a 40-page contract, taps it in your app, and nothing happens for four seconds. Then the whole thing renders at once, scrolls like it is made of lead, and the first customer email of the day says “PDFs are broken on Android”. React Native has no PDF component in core, and the way you get one has changed more in the last twelve months than in the five years before. This guide covers every realistic React Native PDF viewer option in late 2026: the native viewer libraries, the “hand it to the OS” route, WebView and web, and generating PDFs in the first place.
Versions were checked on npm on October 19, 2026: react-native-pdf 7.0.5, react-native-blob-util 0.25.1, @react-native-documents/viewer 4.0.2, react-native-pdf-renderer 2.3.0, expo-print 58.0.6, react-native-pdf-light 3.2.1, @pdftron/react-native-pdf 3.0.4. React Native 0.88.0 and Expo SDK 58 are current.
First decide what “view a PDF” means for you
Three different requirements hide behind that sentence, and they lead to different libraries.
- Show it inside my screen. The PDF is part of your UI: a document tab in a case file, a receipt under an order, a page-by-page reader with your own toolbar. You need a view component.
- Just open it. The user tapped an attachment and wants to read it, zoom it, maybe share it. The OS already has an excellent viewer. You need a one-line call.
- Annotate, sign, fill forms, search text. That is a document SDK, not a viewer, and it is a licence conversation.
Most apps are in the second group and install something from the first group anyway. Start with the decision, not the download count.
Option 1: react-native-pdf (the in-screen default)
react-native-pdf is the component most people mean when they say “the PDF library”. It pulls around 360,000 downloads a week, is MIT licensed, renders through PDFKit on iOS and a PdfiumAndroid fork on Android, and supports URLs, local files, assets and base64, with caching, horizontal or vertical paging, pinch zoom, page jumps and password-protected files. Version 7.0.5 (August 2026) added text selection on iOS, fixed an Android IllegalStateException: Already closed crash and fixed the initial scroll offset on iOS; 7.0.0 brought Android 16 KB page size support and a New Architecture example on 0.81.
It depends on react-native-blob-util for file access, so you install both:
npm install react-native-pdf react-native-blob-util
cd ios && pod install
On Expo you need a development build, not Expo Go, plus the out-of-tree config plugin from @config-plugins/react-native-pdf. Bare Android projects still want the packagingOptions { pickFirst 'lib/**/libc++_shared.so' } block from the README when another native library ships the same runtime.
import Pdf from 'react-native-pdf';
import { useState } from 'react';
import { View, Text, StyleSheet, useWindowDimensions } from 'react-native';
export function ContractViewer({ uri }: { uri: string }) {
const { width } = useWindowDimensions();
const [pages, setPages] = useState(0);
const [page, setPage] = useState(1);
return (
<View style={styles.container}>
<Pdf
source={{ uri, cache: true }}
trustAllCerts={false}
onLoadComplete={(numberOfPages) => setPages(numberOfPages)}
onPageChanged={(current) => setPage(current)}
onError={(error) => console.warn('pdf', error)}
style={{ flex: 1, width }}
/>
<Text style={styles.counter}>{page} / {pages}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
counter: { textAlign: 'center', padding: 8 },
});
Two props people miss. cache: true writes the download next to the app’s cache directory so the second open is instant, and trustAllCerts defaults to true on older versions, which you do not want in a production build that fetches contracts over HTTPS. Set it to false explicitly.
Where it falls short: no text search or selection on Android, no annotations, no form filling, and the Android renderer draws every page as a bitmap, so a 200-page scan at full width eats memory fast. Set scale and minScale sensibly and avoid rendering inside a ScrollView, which fights the component’s own scrolling.
Option 2: hand it to the operating system
If the requirement is “let the user read this file”, the best viewer on both platforms is already installed. iOS has QLPreviewController (Quick Look), Android has whatever handles application/pdf, usually Google’s PDF viewer or Files. @react-native-documents/viewer wraps exactly that:
npm install @react-native-documents/viewer
import { viewDocument } from '@react-native-documents/viewer';
await viewDocument({ uri: localFileUri, mimeType: 'application/pdf' });
It is MIT, needs React Native 0.79 or newer, sits at around 20,000 downloads a week, and 4.0.2 shipped on October 18, 2026. Pair it with @react-native-documents/picker (12.0.3, the maintained successor to react-native-document-picker) when users also need to choose a file. The trade: you get zero control over the UI, and on Android the result depends on which apps the user has installed. For attachments in a chat or an email-style inbox that is exactly right. The system viewer also handles the things you would otherwise ship yourself, like share sheets, printing and AirDrop.
On Expo the equivalent is expo-sharing for the share sheet and WebBrowser.openBrowserAsync for remote files, and there is a cheaper trick for remote PDFs on iOS: a WebView renders them natively (more on that below).
Option 3: react-native-pdf-renderer for huge files
react-native-pdf-renderer takes a different approach. It renders pages lazily with the platform renderers (PdfRenderer on Android, PDFKit on iOS) and only draws pages close to the viewport, so a 2,000-page file opens in the same time as a 2-page one. MIT, 2.3.0 from August 2025, about 26,000 downloads a week, needs React Native 0.71+. It only takes a local file path, so you download first:
import PdfRendererView from 'react-native-pdf-renderer';
<PdfRendererView
style={{ flex: 1 }}
source={localPath}
distanceBetweenPages={16}
maxZoom={5}
onPageChange={(current, total) => setStatus(`${current + 1}/${total}`)}
/>
No horizontal paging, no password support, no text, and the project has been quiet for a year. Pick it when memory is the problem and nothing else.
Option 4: WebView and the web target
iOS WebViews render PDFs natively, so <WebView source={{ uri: 'https://example.com/doc.pdf' }} /> works on iOS with no extra library. Android WebView does not render PDFs; it downloads them. The usual workaround is the Google Docs viewer URL (https://docs.google.com/gview?embedded=true&url=...), which only works for public files and is not something to build on. For the web target of an Expo app, an <iframe> or react-pdf (pdf.js) is the normal answer; react-native-pdf itself has no web implementation. The WebView guide on this site covers the sandboxing you need before loading third-party documents in a WebView at all.
Option 5: commercial SDKs when you need annotations or signatures
Text search on Android, highlights, sticky notes, form filling, redaction and e-signatures are a different product category. @pdftron/react-native-pdf (Apryse, 3.0.4 in September 2026) and Nutrient (formerly PSPDFKit) both ship React Native wrappers with that feature set and both are priced per app or per year with a licence key. The open-source libraries above will not get you there with a weekend of hacking; the Android side alone (PdfiumAndroid has no annotation layer) is months of work. If the feature is on the roadmap, budget for the SDK.
Lightweight alternative: react-native-pdf-light
react-native-pdf-light (3.2.1, May 2026, MIT) renders with the platform renderers like pdf-renderer but exposes single pages and a paged view, with no third-party native dependencies at all. About 2,500 downloads a week. It is the smallest binary footprint on this list, which matters if you are already fighting a 16 KB page size or an APK size budget.
Generating PDFs: expo-print and friends
Often the PDF you want to show is one you need to create: an invoice, a report, a filled-in form. expo-print (58.0.6 on SDK 58, around 455,000 downloads a week) takes HTML and gives you a file on both platforms:
import * as Print from 'expo-print';
import { shareAsync } from 'expo-sharing';
const { uri } = await Print.printToFileAsync({
html: `<h1>Invoice #${invoice.id}</h1><p>Total: ${invoice.total}</p>`,
width: 595, // A4 at 72 dpi
height: 842,
});
await shareAsync(uri, { UTI: '.pdf', mimeType: 'application/pdf' });
It works in bare apps too through Expo modules. For anything beyond HTML-to-PDF (merging, stamping, page extraction) you are back to native code or a server. react-native-pdf-lib, the old answer, was last published in 2020 and should not go into a new project.
Downloading and caching
Whatever viewer you pick, download the file first for anything larger than a page or two. Remote URIs passed straight into a viewer give you no progress, no retry and no offline behaviour. react-native-blob-util (0.25.1, September 2026) is already in your tree if you use react-native-pdf, and 0.25.0 added custom CA certificates for TLS evaluation, which enterprise deployments with private certificate chains will appreciate. Expo apps use expo-file-system:
import { File, Paths } from 'expo-file-system';
const file = new File(Paths.cache, `${docId}.pdf`);
if (!file.exists) {
const out = await File.downloadFileAsync(remoteUrl, Paths.cache);
// out.uri is the local path for any viewer above
}
Cache by document id plus version, not by URL: signed URLs change every request and you will otherwise download the same contract on every open.
Common bugs
- Blank page on iOS after upgrade. react-native-pdf 6.x on React Native 0.7x with the New Architecture rendered nothing; 7.0.0 fixed it. Upgrade rather than patch.
- Android crash “Already closed”. Fixed in 7.0.5. The trigger was unmounting the viewer while a page was still rendering.
- Duplicate
libc++_shared.soat build time. Add thepickFirstpackaging options toandroid/app/build.gradle. - Expo Go shows a red screen. None of the native viewers run in Expo Go. Use
npx expo run:iosor an EAS development build. - Scroll fights the parent. Give the viewer
flex: 1in its own screen and do not nest it in aScrollView. For a sheet-style preview use a bottom sheet with a fixed height instead. - Password-protected files. react-native-pdf takes a
passwordprop; the system viewer prompts the user; pdf-renderer does not support them.
Which one to use
| Need | Use | Why |
|---|---|---|
| Open an attachment the user tapped | @react-native-documents/viewer |
System viewer, share and print for free, nothing to maintain |
| PDF inside your own screen with paging and zoom | react-native-pdf |
Most features, biggest community, 7.x is New Architecture ready |
| Hundreds of pages on low-end Android | react-native-pdf-renderer |
Lazy page rendering, flat memory |
| Smallest native footprint | react-native-pdf-light |
Platform renderers only, no third-party native deps |
| Annotations, forms, signatures, search | Apryse or Nutrient SDK | Open-source viewers do not have an annotation layer |
| Create the PDF | expo-print |
HTML in, file out, both platforms |
| Web target | react-pdf or an iframe |
No native viewer has a web implementation |
My default for a new app in late 2026: the system viewer for attachments, react-native-pdf only for screens where the document is the product, and expo-print for generation. That combination has the least native code to own, and native code you do not own is native code that cannot break on the next Xcode. If your document flow lives inside a messaging feature, our guide to building a React Native chat app covers the file upload side.
FAQ
Does React Native have a built-in PDF viewer?
No. Core ships no PDF component. On iOS a WebView renders remote PDFs natively; everything else needs a library or the system viewer.
What is the best PDF viewer library for React Native?
react-native-pdf for an in-screen viewer with paging, zoom and caching; @react-native-documents/viewer when the platform’s own viewer is enough. For annotations or signatures, a commercial SDK.
Does react-native-pdf work with Expo?
Yes, in a development build or EAS build with the @config-plugins/react-native-pdf plugin. It does not run in Expo Go.
How do I show a PDF from a URL in React Native?
Pass source={{ uri, cache: true }} to react-native-pdf, or download it with expo-file-system or react-native-blob-util first and open the local path in any viewer.
Can I generate a PDF in React Native?
expo-print‘s printToFileAsync turns HTML into a PDF on both platforms. For merging or editing existing PDFs you need native code or a server.