Skip to main content

Quick Start

Build your first PDF viewer in 5 minutes! This guide will walk you through creating a fully functional PDF viewer with JSI acceleration.

Basic PDF Viewer

Let's start with the simplest possible PDF viewer:

App.js
import React from 'react';
import { StyleSheet, View } from 'react-native';

const PdfModule = require('react-native-pdf-jsi');
const Pdf = PdfModule.default;

export default function App() {
return (
<View style={styles.container}>
<Pdf
source={{ uri: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' }}
style={styles.pdf}
/>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
},
pdf: {
flex: 1,
},
});

That's it! You now have a working PDF viewer with automatic JSI acceleration.

Adding Event Handlers

Let's make it more interactive by adding event handlers:

App.js
import React, { useState } from 'react';
import { StyleSheet, View, Text } from 'react-native';

const PdfModule = require('react-native-pdf-jsi');
const Pdf = PdfModule.default;

export default function App() {
const [currentPage, setCurrentPage] = useState(0);
const [totalPages, setTotalPages] = useState(0);

return (
<View style={styles.container}>
{/* Page counter */}
<View style={styles.header}>
<Text style={styles.pageText}>
Page {currentPage} of {totalPages}
</Text>
</View>

{/* PDF Viewer */}
<Pdf
source={{ uri: 'https://example.com/document.pdf' }}
style={styles.pdf}
onLoadComplete={(numberOfPages, filePath, size, tableContents) => {
console.log(`PDF loaded: ${numberOfPages} pages`);
setTotalPages(numberOfPages);
}}
onPageChanged={(page, numberOfPages) => {
console.log(`Current page: ${page}`);
setCurrentPage(page);
}}
onError={(error) => {
console.error('PDF Error:', error);
}}
/>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
},
header: {
padding: 16,
backgroundColor: '#0066cc',
alignItems: 'center',
},
pageText: {
color: 'white',
fontSize: 16,
fontWeight: '600',
},
pdf: {
flex: 1,
},
});

Loading from Different Sources

From URL

<Pdf source={{ uri: 'https://example.com/document.pdf' }} />

From Local File

<Pdf source={{ uri: 'file:///path/to/document.pdf' }} />

From Base64

<Pdf source={{ uri: 'data:application/pdf;base64,YOUR_BASE64_STRING' }} />

From Assets (iOS/Android)

// iOS
<Pdf source={require('./assets/document.pdf')} />

// Android
<Pdf source={{ uri: 'bundle-assets://document.pdf' }} />

Common Props

Here are the most commonly used props:

<Pdf
// Source
source={{ uri: 'https://example.com/document.pdf' }}

// Password (if PDF is protected)
password="yourpassword"

// Scroll direction
horizontal={false} // false = vertical, true = horizontal

// Initial page
page={1}

// Zoom scale
scale={1.0}

// Fit policy
fitPolicy={0} // 0=width, 1=height, 2=both

// Enable antialiasing
enableAntialiasing={true}

// Event handlers
onLoadComplete={(numberOfPages, filePath, size, tableContents) => {}}
onPageChanged={(page, numberOfPages) => {}}
onError={(error) => {}}
onPageSingleTap={(page) => {}}
onScaleChanged={(scale) => {}}

// Style
style={{ flex: 1 }}
/>

Control which page is displayed programmatically:

import React, { useState, useRef } from 'react';
import { View, Button } from 'react-native';

const PdfModule = require('react-native-pdf-jsi');
const Pdf = PdfModule.default;

export default function App() {
const [page, setPage] = useState(1);

const goToNextPage = () => setPage(prev => prev + 1);
const goToPrevPage = () => setPage(prev => Math.max(1, prev - 1));
const goToPage = (pageNum) => setPage(pageNum);

return (
<View style={{ flex: 1 }}>
<View style={{ flexDirection: 'row', padding: 10 }}>
<Button title="Previous" onPress={goToPrevPage} />
<Button title="Next" onPress={goToNextPage} />
<Button title="Go to 5" onPress={() => goToPage(5)} />
</View>

<Pdf
source={{ uri: 'https://example.com/document.pdf' }}
page={page}
onPageChanged={(newPage) => setPage(newPage)}
style={{ flex: 1 }}
/>
</View>
);
}

Fit Policies

Control how the PDF fits within the viewport:

// FitPolicy options:
// 0 = FitWidth (fit to width, scroll vertically)
// 1 = FitHeight (fit to height, scroll horizontally)
// 2 = FitBoth (fit entire page in viewport)

<Pdf
source={{ uri: 'https://example.com/document.pdf' }}
fitPolicy={0} // Fit to width
style={{ flex: 1 }}
/>

Handling Password-Protected PDFs

import React, { useState } from 'react';
import { View, TextInput, Button, Alert } from 'react-native';

const PdfModule = require('react-native-pdf-jsi');
const Pdf = PdfModule.default;

export default function App() {
const [password, setPassword] = useState('');
const [isUnlocked, setIsUnlocked] = useState(false);

const handleError = (error) => {
if (error.message && error.message.includes('password')) {
Alert.alert('Password Required', 'This PDF is password-protected');
}
};

if (!isUnlocked) {
return (
<View style={{ flex: 1, padding: 20, justifyContent: 'center' }}>
<TextInput
placeholder="Enter PDF password"
value={password}
onChangeText={setPassword}
secureTextEntry
style={{ borderWidth: 1, padding: 10, marginBottom: 10 }}
/>
<Button title="Unlock PDF" onPress={() => setIsUnlocked(true)} />
</View>
);
}

return (
<View style={{ flex: 1 }}>
<Pdf
source={{ uri: 'https://example.com/protected.pdf' }}
password={password}
onError={handleError}
style={{ flex: 1 }}
/>
</View>
);
}

JSI Verification

Want to verify that JSI is actually working? Check the console:

const PdfModule = require('react-native-pdf-jsi');
const Pdf = PdfModule.default;

<Pdf
source={{ uri: 'https://example.com/document.pdf' }}
onLoadComplete={(numberOfPages, filePath, size, tableContents) => {
// JSI-enabled builds will log performance metrics
console.log('PDF loaded with JSI acceleration');
}}
style={{ flex: 1 }}
/>
Android onLoadComplete Fix

As of v4.1.0, the onLoadComplete callback now works reliably on Android. The callback receives four parameters: (numberOfPages, filePath, size, tableContents). See What's New in v4.1.0 for details.

Look for logs like:

  • 📱 PDFJSI: JSI availability on android: AVAILABLE
  • 🚀 PDFJSI: High-performance JSI mode enabled

Next Steps

Now that you have a basic PDF viewer working, explore more advanced features:

Common Patterns

Loading Indicator

import React, { useState } from 'react';
import { View, ActivityIndicator } from 'react-native';

const PdfModule = require('react-native-pdf-jsi');
const Pdf = PdfModule.default;

export default function App() {
const [loading, setLoading] = useState(true);

return (
<View style={{ flex: 1 }}>
{loading && (
<View style={{ position: 'absolute', top: '50%', left: '50%' }}>
<ActivityIndicator size="large" color="#0066cc" />
</View>
)}

<Pdf
source={{ uri: 'https://example.com/document.pdf' }}
onLoadComplete={() => setLoading(false)}
onError={() => setLoading(false)}
style={{ flex: 1 }}
/>
</View>
);
}

Error Handling

const handlePDFError = (error) => {
if (error.message.includes('404')) {
Alert.alert('Not Found', 'PDF file not found');
} else if (error.message.includes('password')) {
Alert.alert('Password Required', 'This PDF is password-protected');
} else {
Alert.alert('Error', `Failed to load PDF: ${error.message}`);
}
};

Ready for more? Check out the Advanced Features to unlock the full potential of react-native-pdf-jsi!