Skip to content

PDF-SDK 2.4.1 is out.See what’s new

PDF-SDK
Skip to Content
Docs

React Native

@pdfsdk/react-native-pdf-editor opens the native PDF-SDK editor full screen and resolves with the edited file. It's a thin binding over the iOS and Android SDKs, with the same API and option names as the Flutter plugin.

Every type, option and method: React Native API reference.

NeedsVersion
React Native0.87 or later
iOS15 or later, built with Swift Package Manager — no CocoaPods
Android8.0 (API 26) or later, arm64-v8a devices

On iOS, PDF-SDK ships as a Swift package only — there is no podspec. React Native builds an app without CocoaPods from version 0.87, through its Swift Package Manager setup. React Native still marks that setup experimental, so check it against your release process.

1. Add the package

The package comes with your license, as a tarball:

npm install <the package that comes with your license>

On iOS it fetches the PDF-SDK Swift package itself, from the same package URL as the iOS guide. If that URL is a private repository, sign in to it once in Xcode (Settings ▸ Accounts) so the build can fetch it.

2. iOS: Swift Package Manager

An app made from React Native's template is wired for CocoaPods, so convert it once. The package includes two small tools for this; neither runs CocoaPods.

# Remove CocoaPods from the app (run once)
rm -f ios/Podfile ios/Podfile.lock Gemfile Gemfile.lock
python3 node_modules/@pdfsdk/react-native-pdf-editor/tools/strip-cocoapods.py ios/MyApp.xcodeproj/project.pbxproj

Then add an npm script that runs React Native's Swift Package Manager setup. The config command fills in what the React Native CLI would otherwise only learn from a Podfile and a podspec:

// package.json
"scripts": {
  "spm": "cd ios && RCT_SPM_AUTOLINKING_CONFIG_COMMAND='[\"node\",\"node_modules/@pdfsdk/react-native-pdf-editor/tools/rn-config-spm.js\"]' npx react-native spm"
}
npm run spm

Run it once, and again after a fresh clone; open ios/MyApp.xcodeproj (not a workspace) and build. React Native links the package through its own Package.swift, and the PDF-SDK Swift package comes with it.

iOS 27 stops apps that don't use the scene lifecycle at launch, and React Native 0.87's template still creates its window in the app delegate. Move it into a UIWindowSceneDelegate and add UIApplicationSceneManifest to Info.plist — the example app's AppDelegate.swift shows the whole change.

3. Android

Autolinking picks the module up. Add the Maven repository that comes with your license (Gradle doesn't let a library add one to your app), and set the minimum SDK to 26:

// android/build.gradle
allprojects {
    repositories {
        maven { url "${rootDir}/../vendor/pdfsdk/maven" }   // the unzipped bundle, or your registry URL
    }
}
// android/build.gradle (buildscript ext)
minSdkVersion = 26

4. Set your license key

Once, before the first editor. The key lists your app's iOS bundle identifier and Android package name.

import { PdfEditor } from '@pdfsdk/react-native-pdf-editor';

const license = await PdfEditor.setLicenseKey('PE1.eyJ2Ijox…');
if (!license.isLicensed) console.warn(`PDF-SDK: ${license.reason}`);

5. Open the editor

Give it a PDF on disk, or one bundled with the app. It resolves with the path of the edited file, or null if the user closed without saving.

const edited = await PdfEditor.open({
  path: filePath,          // or asset: 'form.pdf' — bundled in the iOS app / Android assets/
  mode: 'annotate',        // optional: the mode to open in
  tool: 'highlight',       // optional: a tool to arm
});
if (edited) await upload(edited);

The result is a new temporary file; pass inPlace: true to overwrite path instead. A bundled asset is copied to a temporary file first, so the original is never written. Opening rejects with a code of bad_args, not_found, already_open, no_activity, write_failed (the edited file couldn't be written) or, on Android, unsupported (a device without arm64-v8a); a user closing the editor is not an error.

6. Customize the editor

const edited = await PdfEditor.open({
  path: filePath,
  configuration: {
    modes: ['annotate', 'fillAndSign'],
    colorScheme: 'dark',
    hiddenTools: ['stamp'],
    hiddenMenuItems: ['print'],
    toolTitles: { signature: 'Approve' },
    modeTitles: { fillAndSign: 'Sign' },
    selectionColor: '#FF2D55',
    handleShape: 'circle',
    toolDefaults: { highlight: { color: '#00C853', opacity: 0.4 } },
    minZoom: 1,
    maxZoom: 2,
  },
});

Every option the Flutter plugin takes, with the same names: modes, tools and menu; names; colour scheme, selection and search colours; fonts (as file paths); first-use tool styles; zoom, haptics and hints; where e-Sign's placement starts (signaturePlacement: 'topRight'). Colours are #RRGGBB strings. Every option, with what it does: PdfEditorConfiguration in the React Native API reference. Custom icons and your own toolbar buttons stay native-only.

Edit documents from code

Everything a user can do in the editor can be done from code, with no UI: read every layer of a page and its properties, replace text in any script (the layer keeps its font, size, colour and position, and the system's fonts fill in letters its font lacks), restyle, move, resize, rotate and restack layers, add text, images and shapes, mark text up, fill and author forms, edit metadata and pages, search, render a page, and save. Every method: PdfDocument in the API reference.

A layer is addressed by its page and an id that keeps naming it while other layers change. Geometry is in page points from the page's top-left corner. Each change is one undo step.

import { PdfDocument } from '@pdfsdk/react-native-pdf-editor';

const doc = await PdfDocument.open(pdfBase64);
for (const block of await doc.textBlocks(0)) {
  const text = await translate(block.text ?? '');
  await doc.setText(block, text, { shrinkToFit: true });
}
const edited = await doc.save();   // base64
await doc.close();

Pass onDocumentReady to PdfEditor.open to get the document the editor is showing: changes appear on screen at once and the user can undo them. It stops working when the editor closes.

await PdfEditor.open({
  path: filePath,
  onDocumentReady: async (doc) => { await doc.addText('Approved', 0, 40, 120); },
});

Bytes (the PDF, PNGs, fonts) are base64 strings, colours #RRGGBBAA. Failures reject with a PdfDocumentError whose code is notFound (read the layers again), unsupportedGlyphs, failed, badArguments or cannotOpen.

Localize the editor

Every word the editor shows has a stable key, the same on every platform, with English as its built-in text. Give text for the keys you want translated; the rest stay English. The editor checks a dictionary first, then the app's own translations (iOS PDFEditor.strings, Android pe_<key> resources) in its current language, then English. Right-to-left languages mirror the editor; the page navigator stays left to right, like the pages it turns.

await PdfEditor.open({
  path: filePath,
  configuration: { localization: { language: 'hi', strings: { cancel: 'रद्द करें' } } },
});

Placeholders are positional (Page {1} of {2}), so a translation can reorder them. A count has two keys: <key>_one and <key>. Names you set per tool, mode or menu item win over translations.

Troubleshooting

SymptomFix
the native module isn't linkedAndroid: rebuild the app. iOS: run npm run spm, then rebuild.
npx react-native spm says the project is CocoaPods-integratedRun strip-cocoapods.py on the project (step 2).
Package.swift is missing for library …Another library in the app ships only a podspec. Generate a Package.swift for it with npx react-native spm scaffold and keep it with npx patch-package <library>, or ask its maintainer to ship one.
The app stops at launch on iOS 27 (NoSceneLifecycleAdoption)Adopt the scene lifecycle (step 2).
Could not find com.pdfsdk:pdfeditorAdd the PDF-SDK Maven repository (step 3).