React Native is an open source framework for building native mobile apps using JavaScript. The resulting apps are indistinguishable from those built in Swift, Objective-C, Kotlin, or Java, because they don't run inside of a webview. The UI for React Native apps is rendered using native views, which provides users with the fluid look and feel of traditional native applications.

In this article we describe how to build a PDF viewer in React Native with react-native-view-pdf to render PDFs on Android and WKWebView for rendering PDFs on iOS. The react-native-view-pdf library uses Android PdfViewer, and by extension PdfiumAndroid as the underlying rendering engine, while WKWebView uses Apple's proprietary PDF renderer.

linkStep 1 - Create a New App

We're going to use the command line, so make sure you have react-native-cli installed. From the command line:

react-native init PDFDemo
cd PDFDemo

linkStep 2 - Add the Libraries

Add the react-native-view-pdf library to the project:

yarn add react-native-view-pdf

If you use npm:

npm install react-native-view-pdf --save

linkStep 3 - Link the Library

After that, you need to link the library:

react-native link react-native-view-pdf

linkStep 4 - Implement the Viewer

The resourceType can be 'file', 'url', or 'base64'. If the resourceType is 'file', the library tries to load the file from the app bundle, so you will need to add the PDF file to the project, and add to app target. For Android, it loads the file from SDCard.

import PDFView from 'react-native-view-pdf';

const resources = {
  file: Platform.OS === 'ios' ? 'test-pdf.pdf' : '/sdcard/Download/test-pdf.pdf',
  url: 'https://www.ets.org/Media/Tests/TOEFL/pdf/SampleQuestions.pdf',
  base64: 'JVBERi0xLjMKJcfs...',
};

export default class App extends React.Component {
  render() {
    const resourceType = 'base64';

    return (
      <View style={{ flex: 1 }}>
        {/* Some Controls to change PDF resource */}
        <PDFView
          fadeInDuration={250.0}
          style={{ flex: 1 }}
          resource={resources[resourceType]}
          resourceType={resourceType}
          onLoad={() => console.log(`PDF rendered from ${resourceType}`)}
          onError={() => console.log('Cannot render PDF', error)}
        />
      </View>
    );
  }
}

And you're done.

This a great solution for basic viewing use cases, but if you need more robust functionality, like annotation, real-time collaboration, form filling, text search, page manipulation, or others, you would have to implement them yourself. Also beware that the Apple and PDFium rendering engines only work well if your documents are simple and you can afford to have some rendering inconsistencies or failures.

For more robust functionality and high fidelity rendering, PDFTron's PDF SDK offers a React Native wrapper for iOS and Android. Some of the features include:

  • Multi-tab viewing makes it easy to flip between documents
  • A collection of different viewing modes such as one page horizontal swiping, two page horizontal swiping, one page vertical swiping, two page vertical swiping and magazine mode
  • Annotation creation & editing
  • Form filling
  • Text search
  • Advanced navigation to find information quickly through a thumbnail slider, document outline, annotations list, and thumbnail grid
  • Page manipulation, including page deletion and rearranging
  • Night mode for a more enjoyable viewing experience in dark environments
  • System file sharing (such as email or to another app)

On Android, it also supports viewing other file extensions such as .docx, .doc, .pptx, .xlsx, .md, .cbz and various image formats. It allows stream conversion of these non-pdf documents to PDF format so you can view the document while conversion happens. Undo/redo and reflow mode are also available on the Android version.

linkBuilding a PDF Viewer with PDFTron

The PDFTron DocumentView component can be used just like any other React Native component:

import { DocumentView } from 'react-native-pdftron';
const RNPdftron = NativeModules.RNPdftron;

export default class App extends Component<Props> {

  onLeadingNavButtonPressed = () => {
    console.log('leading nav button pressed');
    if (Platform.OS === 'ios') {
      Alert.alert(
        'App',
        'onLeadingNavButtonPressed',
        [
          {text: 'OK', onPress: () => console.log('OK Pressed')},
        ],
        { cancelable: true }
      )
    } else {
      BackHandler.exitApp();
    }
  }

  render() {
    const path = Platform.OS === 'ios' ? "sample" : "android.resource://com.myapp/raw/sample.pdf";

    return (
      <DocumentView
        document={path}
        showLeadingNavButton={true}
        leadingNavButtonIcon={Platform.OS === 'ios' ? 'ic_close_black_24px.png' : 'ic_arrow_back_white_24dp'}
        onLeadingNavButtonPressed={this.onLeadingNavButtonPressed}
      />
    );
  }
}

Android Preview:

iOS Preview:

You can find the API documentation for DocumentViewhere.

To get started, you can clone PDFTron's React Native open source wrapper here.

linkConclusion

Building a PDF Viewer with React Native can be straightforward, but once you start needing more advanced features or high-fidelity rendering, open source may not be best approach. PDFTron has hundreds of features, 30+ file formats, and a proven rendering engine built right in, and it's just as simple to implement.

PDFTron SDK for mobile comes with many out-of-the-box controls and tools that can be wrapped in React Native. If you are interested to see any of the controls and tools in React Native, please feel free to contact us or submit a feature request. You are also very welcome to improve our open source React Native wrapper. Please submit a pull request if you are interested. Stay tuned for future improvements on PDFTron React Native wrapper!