The New Year Sale is Live!

MarketPlace Logo

Dec 16, 2025

Dot

4 min read

A Developer's Guide to React Native PDF Handling

Author

Riya

A Developer's Guide to React Native PDF Handling

Working with PDFs in a React Native app isn't some niche, edge-case feature anymore. It’s a core function for tons of apps out there. Whether you're generating an invoice, showing a signed contract, or letting users share a report, how your app handles documents says a lot about its quality and professionalism.

Why You Need to Nail Your PDF Workflow

In the mobile world, PDFs are the gold standard for official documents. Think financial reports, legal agreements, or even simple concert tickets—users just expect this stuff to work flawlessly. A clunky or unreliable PDF experience is a surefire way to frustrate people and make your app feel amateur.

This is where getting the right tools and techniques down in React Native is so critical. This guide is a practical, end-to-end roadmap for building out solid PDF features. We’re going to skip the high-level theory and get right into the real-world problems developers hit, like weird cross-platform quirks and performance bottlenecks.

The Three Pillars of PDF Integration

When you get right down to it, successfully adding PDF capabilities to your app means mastering three key areas:

  • Generation: Creating pixel-perfect documents on the fly using your app's data or even rendering components directly to a PDF.
  • Viewing: Providing a smooth, responsive viewer that doesn't choke on large or complex documents.
  • Sharing: Making it dead simple for users to export and send those PDFs to other apps or people.

The need for these skills is only growing. The global market for React Native app development was valued at USD 325 million in 2024 and is expected to hit USD 499 million by 2031. A big reason for that growth is efficiency, with developers seeing up to 90% code reusability between iOS and Android. Nailing common features like PDF handling just makes the whole ecosystem more valuable.

A great PDF experience should feel invisible. The document just shows up, scrolls like butter, and shares without a second thought. The moment a user has to stop and think about the process, you've already lost.

And for apps that handle sensitive information, you might need to go a step further. Understanding this guide to digitally signing PDFs can be indispensable for adding that extra layer of security and trust.

Ultimately, my goal here is to help you make PDF handling a strength in your React Native projects, not a recurring headache.

Choosing the Right React Native PDF Library

Picking the right library is your first big decision when adding PDF features to your app, and it’s a critical one. The React Native ecosystem has some great options, but they are definitely not one-size-fits-all. The library you go with will shape everything from development time and performance to the final user experience.

The most basic split you'll find is between libraries for viewing existing PDFs and those for generating new ones from scratch. Some tools are masters of one, while a few try to handle both. Let's dig into the factors that really matter when you're making this call.

Key Decision Factors

Before you even think about installing a package, take a step back and look at your project's needs.

  • What’s the main goal? Are you just displaying static documents like terms of service or user manuals? Or do you need to create dynamic, data-driven files like invoices, tickets, or custom reports?
  • Which platforms are you targeting? You'll obviously want things to work smoothly on both iOS and Android. While React Native is fantastic for cross-platform development, some PDF libraries can have weird little quirks on one platform or the other.
  • Are you using Expo Go or a bare workflow? This is a huge fork in the road. Many of the most powerful PDF libraries need custom native code, which simply won't work in the managed Expo Go environment.

This decision tree can help you visualize that initial choice, mapping your app's needs to the right kind of tool.

A decision tree flowchart outlines a PDF workflow, guiding choices based on app needs for simple or complex data.

As you can see, the more complex your data and security needs, the more you'll lean towards robust generation libraries over simple viewers.

Top Contenders for Viewing and Generation

When you start looking around, two libraries pop up again and again as solid, reliable choices: react-native-pdf for viewing and react-native-html-to-pdf for generation. They take very different approaches to solving the PDF puzzle and are great benchmarks for what's out there.

react-native-pdf is the gold standard for rendering PDF documents inside your app. It hooks directly into the native rendering engines (PDFKit on iOS, AndroidPdfViewer on Android), which makes it incredibly fast and efficient. It can handle massive files and supports features like zooming, password protection, and smooth scrolling. The catch? It requires linking native dependencies, so it’s best for bare React Native projects.

On the other side of the coin, react-native-html-to-pdf is a fantastic choice for creating documents on the fly. It lets you use standard HTML and CSS to design your layout, which is a massive win for developers. You can easily whip up an invoice or generate a concert ticket using data straight from your app's state. It also relies on native print services, so you'll be doing some native setup here, too.

The real challenge isn't just making a PDF. It's making it look good without tearing your hair out. Converting complex CSS into a print-friendly format is where you'll run into the trickiest bugs and layout headaches.

Comparing Your Options Side-by-Side

To really nail down your choice, it helps to see the main players compared directly. Often, the best fit comes down to balancing ease of use, performance, and whether a library plays nice with your project's setup.

Comparison of Popular React Native PDF Libraries

This table breaks down the key features of the leading libraries, helping you pick the right tool for viewing, generating, or even modifying PDFs in your app.

Library Primary Use Case Expo Go Compatible Native Dependencies Key Feature
react-native-pdf Viewing PDFs No Yes (iOS/Android) High-performance rendering of large/complex files.
react-native-html-to-pdf Generating PDFs No Yes (iOS/Android) Creates PDFs from HTML strings, great for dynamic content.
react-native-view-shot Generating PDFs Yes No (mostly JS) Captures a React component as an image or PDF.
pdf-lib Manipulating PDFs Yes No (pure JS) Excellent for modifying existing PDFs (e.g., adding text).

As you can see, the need for native dependencies is the biggest differentiator. It's the classic trade-off between power and simplicity.

Expo Considerations and Native Dependencies

The "Expo question" is a common roadblock. If you’re building and testing with Expo Go, you're pretty much limited to pure JavaScript libraries like pdf-lib or react-native-view-shot. These are great for simple tasks but just don't have the muscle or advanced features of their native-backed cousins. For a deeper look at this, our Expo React Native tutorial offers more context on managing project dependencies.

If your app needs serious PDF power, you'll almost certainly need a library with native modules. That means you're either working with a bare React Native project from the start or using Expo's EAS Build service to create a custom development build. This path unlocks full native performance but adds another layer of complexity to your setup.

This trade-off is at the heart of the React Native experience. The framework's biggest strength is its code reusability—you can share around 90% of your code between platforms, which can slash development time by up to 50%. One UK insurer, for instance, built a full MVP in just six weeks by taking advantage of this efficiency.

Ultimately, your choice comes down to one thing: aligning a library's capabilities with your project's specific needs, constraints, and workflow.

Generating PDFs from Your React Components

Sometimes, just displaying a static, pre-made PDF isn't enough. When you need to create dynamic documents on the fly—think invoices, event tickets, or custom reports—generating them directly from your app's data is the way to go. This approach lets you build a React Native PDF using your existing components and state, ensuring every document is up-to-date and tailored to the user.

Let's walk through how to do this with react-native-html-to-pdf, a really popular library for this exact task. Its biggest advantage is that it plays to your strengths as a web developer. If you know HTML and CSS, you already know how to design a great-looking PDF.

A blue block with 'Generate PDF' text, alongside a document, notebook, pen, and smartphone, on a wooden table.

Getting Your Environment Ready

First things first, we need to get the library installed and wired up. Because react-native-html-to-pdf does the heavy lifting with native code, the setup is a little more involved than a pure JavaScript package.

Here’s the drill:

  1. Install the package: Pull the library into your project. npm install react-native-html-to-pdf --save
  2. Link native code: For React Native 0.60 and up, autolinking should take care of most of this. For iOS, you'll still need to hop into the ios directory and install the pods. cd ios && pod install
  3. Set Android permissions: Your app needs permission to save files. Open up your AndroidManifest.xml and add the WRITE_EXTERNAL_STORAGE permission. Keep in mind that for newer Android versions, you'll also have to request this permission at runtime. We'll get to that in a bit.

Turning JSX into a PDF

The core idea here is brilliantly simple: you create an HTML string that represents your document, and the library handles the conversion to a PDF file. This means you can use all the familiar HTML tags and CSS you already know to structure and style your document.

Let's say you're building an app for a tech conference and need to generate a simple ticket for attendees. The ticket should show their name, a QR code, and some event details.

You can start by creating a function that takes the attendee's data and spits out a complete HTML string.

const createTicketHTML = (attendee) => { return <html> <head> <style> body { font-family: 'Helvetica Neue', 'Helvetica', Arial, sans-serif; padding: 20px; } .ticket { border: 1px solid #ccc; padding: 15px; text-align: center; } h1 { font-size: 24px; margin-bottom: 5px; } p { font-size: 16px; color: #555; } img { width: 150px; height: 150px; margin-top: 15px; } </style> </head> <body> <div class="ticket"> <h1>React Native Conf 2024</h1> <p>Attendee: <strong>${attendee.name}</strong></p> <p>Seat: ${attendee.seat}</p> <img src="data:image/png;base64,${attendee.qrCodeBase64}" /> </div> </body> </html>; }; This function is your PDF engine. It takes raw data and merges it with an HTML template to create a personalized document every single time.

Tying It All Together in a Component

Now, let's plug this into a React Native component. We'll import the library, set up some sample data, and create a function that kicks off the whole process.

The createPDF function is where the magic happens. It calls our HTML generator, sets a few options, and then hands everything over to the library's convert method.

import React from 'react'; import { View, Button, Alert } from 'react-native'; import RNHTMLtoPDF from 'react-native-html-to-pdf';

// Assuming createTicketHTML is defined above or imported

const TicketGenerator = () => { const createPDF = async () => { const attendeeData = { name: 'Jane Doe', seat: 'A12', qrCodeBase64: 'iVBORw0KGgoAAAANSUhEUgAAAAUA...', // A valid base64 string };

const htmlContent = createTicketHTML(attendeeData);

let options = {
  html: htmlContent,
  fileName: `Ticket-JaneDoe`,
  directory: 'Documents',
};

try {
  const file = await RNHTMLtoPDF.convert(options);
  console.log(file.filePath);
  Alert.alert('Success', `PDF created at: ${file.filePath}`);
} catch (error) {
  console.error('Failed to create PDF:', error);
  Alert.alert('Error', 'Could not create the PDF.');
}

};

return ( <View> <Button title="Generate My Ticket" onPress={createPDF} /> </View> ); };

export default TicketGenerator;

When a user taps that button, our code generates the HTML, passes it off to the native module, and saves the final PDF to the device's documents folder. The filePath it returns is super important—you'll need it later to open or share the file.

Pro Tip: One of the most common snags I see is with CSS compatibility. The native PDF engines don't support every modern CSS property. To avoid headaches, stick to well-supported basics like font-size, color, margin, padding, and flexbox for layouts.

Navigating Common Challenges

While the basics are pretty straightforward, you'll inevitably run into a few hurdles in a real-world app. Getting that generated PDF to look just right takes some finessing.

Here are a few tips I've picked up to sidestep common issues:

  • Embedding Images: Remote image URLs are a no-go. They almost always fail to load in the final PDF. To get images to render reliably, you have to base64 encode them first and embed the string directly into the <img> tag's src attribute.
  • Custom Fonts: Want to use your brand's font? You'll need to include the .ttf or .otf font files in your native project's assets folder. Then, you can reference them in your CSS using @font-face. This setup is platform-specific, so be sure to check the library's docs for both iOS and Android.
  • Styling Mismatches: What looks perfect in your browser might look a little… off… in the PDF. Always, always test your generated documents on actual devices. A few minor CSS tweaks are often all it takes to get a pixel-perfect React Native PDF.

Getting a Seamless PDF Viewer into Your App

So you’ve generated a PDF—great. Now, how do you actually show it to the user? The last thing you want is a clunky, slow-loading viewer that makes an otherwise slick app feel broken. This is where embedding a smooth, native-feeling viewer becomes non-negotiable for a solid React Native PDF workflow.

A hand holds a smartphone displaying a content-rich app, with a blue overlay box saying "Smooth PDF Viewer" in an outdoor setting.

For this job, my go-to library is react-native-pdf. It's a powerhouse that uses native rendering for buttery-smooth performance on both iOS and Android. It handles all the essentials right out of the box, from pinch-to-zoom and page navigation to loading documents from a remote server or right from the device's storage.

Setting Up the PDF Viewer Component

Getting react-native-pdf up and running is pretty straightforward. But since it taps into native code, this is one for bare React Native projects or custom Expo development builds. Managed Expo workflow won't cut it here.

After you install the package and link the native bits (pod install is your friend on iOS), the next step is to wrap it in a dedicated viewer component. The heart of the library is the <Pdf /> component, and it just needs a source object to know what to display.

Let's start with a basic setup for pulling a PDF from a remote URL.

import React from 'react'; import { StyleSheet, View, ActivityIndicator } from 'react-native'; import Pdf from 'react-native-pdf';

const PDFViewer = ({ pdfUrl }) => { const source = { uri: pdfUrl, cache: true };

return (
    <View style={styles.container}>
        <Pdf
            source={source}
            onLoadComplete={(numberOfPages, filePath) => {
                console.log(`Number of pages: ${numberOfPages}`);
            }}
            onError={(error) => {
                console.log(error);
            }}
            style={styles.pdf}
        />
    </View>
);

};

const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'flex-start', alignItems: 'center', }, pdf: { flex: 1, width: '100%', height: '100%', } });

export default PDFViewer;

See that cache: true property? It’s a tiny detail with a huge impact. It tells the library to store the remote PDF locally after the first download, so every subsequent view is practically instant.

Handling Different PDF Sources

In the real world, your PDFs won't all live in the same place. The source prop is built for this flexibility, handling different scenarios with just a minor tweak.

  • Remote URLs: Just like we saw, an object with a uri key is all you need. Perfect for documents living on a server.
  • Local Device Files: If you've just generated a PDF and have its filePath, you can pop it right into the viewer by prefixing the path with file://.
  • Static Assets: For PDFs you've bundled with your app (like a terms of service or a user guide), require('./assets/manual.pdf') does the trick.

One of the most common mistakes I see developers make is forgetting to handle loading and error states. Always show a loading spinner (ActivityIndicator) while the PDF is being fetched and a clear error message if something goes wrong. It’s a small touch that makes your app feel professional and responsive instead of just frozen.

The fact that we have such reliable libraries is a sign of a mature ecosystem. The job market reflects this, too. As of 2025, a quick search on LinkedIn shows 6,413 job postings for React Native developers in the US alone. This framework is a dominant force, and the demand for developers who can master these workflows is huge.

Advanced Features and User Controls

A truly great viewer does more than just display a document—it gives users the controls they expect. react-native-pdf comes packed with props to level up the user experience.

  • horizontal={true}: Flips the scroll direction, letting users swipe through pages like a book.
  • enablePaging={true}: This is fantastic for document-style viewing. It snaps the view to the top of each page as the user scrolls.
  • password="your-password": Got a protected PDF? This prop lets the component decrypt and display it seamlessly.
  • onPageChanged={(page, numberOfPages) => { ... }}: This callback fires every time the user turns a page. It’s perfect for building a custom "Page X of Y" counter in your UI.

Implementing these features makes your in-app viewer feel just as powerful as a dedicated PDF reader. This is just one piece of the puzzle, of course. For a deeper dive, check out our guide on the best React Native PDF viewer libraries out there. By putting these tools together, you can create a truly polished and high-performing document experience right inside your app.

Advanced PDF Techniques and Performance Tuning

Once you've got the basics of generating and viewing a PDF in React Native down, it's time to start thinking about the user experience. This is where advanced techniques come in. It’s less about just creating the document and more about how your app behaves in the process, especially when you're dealing with big or complex files that can really bog down a device.

The number one performance killer I see is generating a hefty PDF right on the main JavaScript thread. If you're building a multi-page report packed with data and images, this can easily lock up the UI for several seconds. Your app will feel frozen and totally unresponsive. The fix? Offload that heavy lifting to a background thread.

Preventing UI Freezes with Background Processing

Running intensive tasks in the background is just standard practice in mobile development. While React Native doesn’t have a super straightforward built-in multithreading solution like native platforms do, libraries such as react-native-thread can get the job done by executing JavaScript code off the main thread.

By shifting your PDF generation logic into a separate worker, you keep the user interface buttery smooth and interactive. This approach is absolutely essential for apps that need to spit out detailed invoices, financial statements, or any document that has to pull and crunch a lot of data before rendering. The user can keep tapping around the app while their report is being built, and they'll just get a notification when the file is ready to go.

A responsive UI is non-negotiable. The moment a button press leads to a frozen screen, user trust plummets. Offloading a task as heavy as PDF generation isn't just a performance tweak; it's a fundamental part of building a reliable, professional application.

Mastering File System Management and Sharing

Making the PDF is only half the battle. You also have to manage it properly. That means saving the file somewhere accessible, letting users share it, and cleaning up old files so you don't hog their storage.

A solid file management strategy usually involves a few key things:

  • Saving to a predictable spot: Use a library like react-native-fs to save documents to standard locations, like the app's Documents or Cache directory.
  • Giving users access: Once it's saved, you can either open the file with the device's default PDF viewer or let them share it.
  • Cleaning up after yourself: You should build in some logic to delete temporary or outdated PDFs. This is crucial for apps that generate a lot of documents over time.

To handle sharing, React Native's built-in Share API is the perfect tool. It pops open the native sharing dialog on both iOS and Android, allowing users to send their PDF to email, messaging apps, or cloud storage with a single tap.

import { Share } from 'react-native';

const sharePDF = async (filePath) => { try { await Share.share({ title: 'Share Your Document', url: file://${filePath}, // Crucial to add the file:// protocol }); } catch (error) { console.error('Error sharing PDF:', error.message); } };

This simple function opens up a world of interoperability, making your app a genuinely useful tool in your user's day-to-day workflow.

Navigating Platform-Specific Permissions

Finally, you can't read or write files without the user's permission. Modern versions of Android and iOS have really strict rules about file system access, and your app has to request what it needs correctly. Forgetting this step is a classic reason why react native pdf features fail silently.

On Android, you’ll need to request WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE permissions, which you'll typically handle with the PermissionsAndroid module. iOS is a bit more straightforward but will require you to add descriptions for file access in your Info.plist file. Making sure your app handles these permissions gracefully is a critical final check. For those just getting started, our guide to a complete React Native setup covers foundational project configurations just like this.

As you dive deeper, don't forget about security. This guide on advanced PDF protection methods, including DRM and watermarks, offers some great insights into safeguarding sensitive documents. When you combine smart performance tuning with solid security, you end up with a truly professional PDF experience.

Got Questions About React Native PDFs? We’ve Got Answers.

When you're knee-deep in code trying to wrangle a React Native PDF feature, it’s easy to hit the same walls other developers have. Let’s cut through the noise and get straight to the answers for some of the most common snags you'll run into.

Getting these little details right is what separates a polished, professional feature from a buggy mess.

How Can I Add Custom Fonts to My Generated PDF?

Ah, the classic "last mile" problem of PDF generation. Getting custom fonts to show up can feel surprisingly tricky, but it boils down to one thing: the native PDF engine needs to be able to find your font files.

This means you have to place your .ttf or .otf files directly into your project's native asset folders.

For a bare React Native project, that usually looks like this:

  • Android: Drop your font files into android/app/src/main/assets/fonts/.
  • iOS: Add the files to your project in Xcode. Critically, you have to make sure they're included in your target's "Copy Bundle Resources" build phase and add a key to your Info.plist file listing them out.

Once that's done, you can usually reference them in your HTML or CSS with an @font-face rule, just like on the web. But always, always check the docs for your chosen library first—some have a streamlined API for registering fonts that can save you a ton of platform-specific headaches.

What Is the Best Way to Handle Large PDF Files?

Nothing kills the user experience faster than a frozen UI or an app crash caused by a massive PDF. Large files are notorious memory hogs, and the secret is to stop trying to load the entire thing into memory at once.

When you're viewing huge PDFs, your best bet is to use a library like react-native-pdf that supports on-demand page rendering. This is a game-changer. It only loads the pages currently on the screen, which dramatically improves performance and keeps memory usage low.

Now, for generating big, data-heavy reports, the smartest move is often to offload the work to a server. Your app just sends the data, the server does the heavy lifting of building the PDF, and then sends the finished file back. If you absolutely must generate it on the client-side, make sure you run the process on a background thread so your UI doesn't lock up.

Can I Use These PDF Libraries with Expo Go?

This is a huge point of confusion for a lot of developers. The short answer? It depends. The long answer is it all comes down to whether the library needs custom native code.

Some simple, JavaScript-only libraries will work just fine inside the Expo Go sandbox. But the most powerful and performant React Native PDF libraries—like react-native-pdf and react-native-html-to-pdf—depend on native modules. That makes them incompatible with Expo Go out of the box.

So, what do you do? You’ve got two solid options. You can create an Expo development build by running npx expo run:android or npx expo run:ios. This bundles your native dependencies into a custom version of the Go app for you to test on. The other path is to eject from the managed workflow entirely and move to a bare React Native project, giving you full native control.


Ready to build your next app without starting from scratch? At gluestack market, we provide production-ready React Native templates that help you launch faster. Check out our full catalog of UI kits and app starters at https://market.gluestack.io.

Our website uses cookies to improve your browsing experience. You can choose to enable or disable cookies, except for the essential ones. To manage permissions, Please click on "Manage Preferences." Read more about how we use cookies on our Cookie Policy page.

Note: For details on our ethical information use, visit our Privacy Policy page.