npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@michelgutner/react-native-pdf-viewer

v0.1.0

Published

High-performance PDF viewer for React Native — New Architecture (Fabric). Uses PDFKit on iOS and PdfRenderer on Android. No native dependencies, no WebViews.

Readme

RNPdfViewer

A high-performance PDF viewer for React Native built on the New Architecture (Fabric). Uses PDFKit on iOS and android.graphics.pdf.PdfRenderer on Android — no native dependencies, no WebViews.

Requirements

| | Version | |---|---| | React Native | ≥ 0.75 (New Architecture required) | | iOS | ≥ 15.1 | | Android | API ≥ 24 |

New Architecture only. The component uses Fabric and Codegen. Legacy Architecture is not supported.


Installation

npm install @michelgutner/react-native-pdf-viewer

iOS

cd ios && pod install

Android

No extra steps. The library uses the built-in PdfRenderer API.


Usage

import RNPdfViewer from '@michelgutner/react-native-pdf-viewer';

<RNPdfViewer
  style={{ flex: 1 }}
  source={{ url: 'https://example.com/document.pdf' }}
  onLoadEnd={e => console.log('loaded', e.nativeEvent.url)}
  onPageChange={e => console.log(`page ${e.nativeEvent.page} of ${e.nativeEvent.totalPages}`)}
/>

Props

Source

| Prop | Type | Description | |---|---|---| | source | { url: string } | HTTP/HTTPS or file:// URL of the PDF |

Display

| Prop | Type | Default | Description | |---|---|---|---| | direction | 'VERTICAL' \| 'HORIZONTAL' | 'VERTICAL' | Scroll direction. Horizontal uses page-snap. | | autoScale | boolean | true | Scale pages to fit the view width | | colorMode | 'default' \| 'night' \| 'sepia' | 'default' | Color theme | | twoPageMode | boolean | false | Show two pages side by side (landscape / tablet) |

Zoom

| Prop | Type | Default | Description | |---|---|---|---| | minZoom | number | 0.25 | Minimum scale factor | | maxZoom | number | 5.0 | Maximum scale factor |

Navigation

| Prop | Type | Description | |---|---|---| | page | number | Jump to this 1-based page number when the value changes |

Search

| Prop | Type | Description | |---|---|---| | searchTerm | string | Highlights all matches in the document | | nextSearchFieldIndex | number | Increment to navigate to the next match | | previousSearchFieldIndex | number | Increment to navigate to the previous match |

Password-protected PDFs

| Prop | Type | Description | |---|---|---| | password | string | Password to unlock a protected PDF |

Loading indicator

| Prop | Type | Default | Description | |---|---|---|---| | loadingEnabled | boolean | true | Show a spinner while the PDF loads | | loadingSize | 'small' \| 'medium' \| 'large' | 'large' | Spinner size |

Thumbnails

| Prop | Type | Description | |---|---|---| | thumbnailWidth | number | Width in pixels for generated thumbnails. 0 disables generation. Fires onThumbnailReady once per page. |

Full-screen page overlay

| Prop | Type | Description | |---|---|---| | fullScreenPage | number | Opens a 1-based page in a full-screen overlay. Set to 0 to close. |

Performance

| Prop | Type | Default | Description | |---|---|---|---| | pageCacheSize | number | 5 | Number of pre-rendered pages to keep in memory (Android) |

Imperative actions

These props work as triggers — increment the value to fire the action once.

| Prop | Type | Description | |---|---|---| | printTrigger | number | Open the system print dialog | | shareTrigger | number | Open the system share sheet |

const [printTrigger, setPrintTrigger] = useState(0);

// fire:
setPrintTrigger(v => v + 1);

<RNPdfViewer printTrigger={printTrigger} ... />

Events

| Event | Payload | Description | |---|---|---| | onLoadStart | { url: string } | PDF download started | | onLoadEnd | { url: string } | PDF is ready and first page is rendered | | onPageChange | { page: number; totalPages: number } | User scrolled to a different page | | onSearchTermData | { totalCount: number; currentIndex: number } | Search completed — total matches and active index | | onError | { message: string } | Download or parse error, or wrong password | | onOutlineReady | { outlineJson: string } | Table of contents available. Parse with JSON.parse(outlineJson)Array<{ title, page, level }> | | onLinkPress | { url: string } | User tapped a link inside the PDF | | onThumbnailReady | { page: number; base64: string } | A page thumbnail is ready (JPEG, base64-encoded) | | onFullScreenClose | { page: number } | User closed the full-screen page overlay |


Examples

Search with navigation

const [term, setTerm] = useState('');
const [next, setNext] = useState(0);
const [prev, setPrev] = useState(0);
const [matches, setMatches] = useState({ totalCount: 0, currentIndex: 0 });

<RNPdfViewer
  source={{ url: PDF_URL }}
  searchTerm={term}
  nextSearchFieldIndex={next}
  previousSearchFieldIndex={prev}
  onSearchTermData={e => setMatches(e.nativeEvent)}
/>

// Navigate:
<Button title="Next"     onPress={() => setNext(v => v + 1)} />
<Button title="Previous" onPress={() => setPrev(v => v + 1)} />

Table of contents

const [outline, setOutline] = useState([]);

<RNPdfViewer
  source={{ url: PDF_URL }}
  onOutlineReady={e => setOutline(JSON.parse(e.nativeEvent.outlineJson))}
/>

{outline.map(item => (
  <Text key={item.page} style={{ paddingLeft: item.level * 16 }}>
    {item.title}
  </Text>
))}

Thumbnails strip

const [thumbs, setThumbs] = useState({});

<RNPdfViewer
  source={{ url: PDF_URL }}
  thumbnailWidth={80}
  onThumbnailReady={e => {
    const { page, base64 } = e.nativeEvent;
    setThumbs(prev => ({ ...prev, [page]: base64 }));
  }}
/>

{Object.entries(thumbs).map(([page, b64]) => (
  <Image
    key={page}
    source={{ uri: `data:image/jpeg;base64,${b64}` }}
    style={{ width: 80, height: 110 }}
  />
))}

Platform notes

| Feature | iOS | Android | |---|---|---| | Render engine | PDFKit | android.graphics.pdf.PdfRenderer | | Search / highlight | ✅ | ✅ API 35+ (silent on older) | | Table of contents | ✅ | ✅ API 35+ (empty on older) | | Clickable links | ✅ | ✅ API 35+ | | Print | ✅ | ✅ | | Share | ✅ | ✅ | | Night / Sepia mode | ✅ | ✅ | | Two-page mode | ✅ | ✅ | | Password-protected PDFs | ✅ | ✅ |


License

MIT