Sign PDFs in React Native
This guide demonstrates how Nutrient React Native SDK allows you to seamlessly integrate electronic signatures into PDF documents within your React Native app. With a built-in, user-friendly interface, end users can tap on a signature field to open a popover and sign a PDF by drawing, typing, or attaching an image. This feature enhances the PDF signing experience, providing a streamlined and customizable solution for document signing.
Activate the Electronic Signatures component within your license to use this feature.
Adding electronic signatures to PDFs on iOS and Android
With Nutrient React Native SDK, you can add electronic signatures within your app on both iOS and Android. The SDK supports multiple input methods, allowing end users to draw, type, or attach an image as a signature.
Adding a signature programmatically
Signatures are handled as annotations in PDFs and can be added programmatically using:
InkAnnotation— For signatures drawn by the userStampAnnotation— For signatures attached as images
For example, to create an ink signature, use the following code in your React Native component:
const inkAnnotation = new InkAnnotation({ pageIndex: 0, bbox: [ 441.99713134765625, 442.6099853515625, 27.155731201171875, 14.720001220703125, ], lineWidth: 0.1887541264295578, lines: { points: [ [ [460.4974365234375, 442.6109619140625], [455.177734375, 442.6500549316406], [451.77471923828125, 443.1976623535156], [446.9244384765625, 444.879638671875], [443.36492919921875, 447.5394592285156], [441.956787109375, 450.0428466796875], [441.4091796875, 453.9152526855469], [442.2305908203125, 455.6754455566406], [443.7951965332031, 456.9271545410156], [446.4550476074219, 457.4747619628906], [450.0927734375, 457.4747619628906], [454.4736633300781, 456.6533508300781], [458.8545837402344, 455.04962158203125], [463.0399169921875, 453.2894287109375], [466.4820556640625, 451.568359375], [469.0245666503906, 449.72991943359375], [469.5721740722656, 448.9476318359375], [469.6504211425781, 448.4000244140625], [468.24224853515625, 447.3439025878906], [463.4310607910156, 446.28778076171875], [458.3069763183594, 446.28778076171875], [452.94818115234375, 447.73504638671875], [449.42779541015625, 449.6517028808594], [447.6676025390625, 451.763916015625], [447.5111389160156, 453.211181640625], [448.1369934082031, 454.2673034667969], [449.5842590332031, 454.8540344238281], [451.9703063964844, 455.010498046875], [454.39544677734375, 454.462890625], [456.1556396484375, 453.3676452636719], [457.3681945800781, 451.88128662109375], [457.91583251953125, 450.8642883300781], [458.2287292480469, 450.1601867675781], [458.3069763183594, 449.72991943359375], [458.38519287109375, 449.26055908203125], [458.38519287109375, 449.0649719238281], [458.42431640625, 448.90850830078125], [458.42431640625, 448.869384765625], ], ], intensities: [ [ 1, 0.123880535364151, 0.41804036498069763, 0.16100835800170898, 0.2891193926334381, 0.33243316411972046, 0.09030450135469437, 0.5518924593925476, 0.5376806259155273, 0.36767661571502686, 0.15482772886753082, 0, 0, 0, 0.10533403605222702, 0.2740456461906433, 0.7828900814056396, 0.8771368265151978, 0.5938639044761658, 0, 0, 0, 0.06578745692968369, 0.36308571696281433, 0.6649492979049683, 0.7192894220352173, 0.640461266040802, 0.4459798336029053, 0.4249451458454132, 0.5206901431083679, 0.5569890141487122, 0.7358735799789429, 0.826309323310852, 0.9041807055473328, 0.895513117313385, 0.9608709812164307, 0.9688565135002136, 0.9975711107254028, ], ], }, strokeColor: "#000000", isSignature: true, isDrawnNaturally: true, opacity: 1, type: "pspdfkit/ink", creatorName: "Test", createdAt: "2025-11-11T12:13:06Z", updatedAt: "2025-11-11T12:13:06Z", name: "A708C088-6E91-4AC7-9380-6B4AD9425853", uuid: "A708C088-6E91-4AC7-9380-6B4AD9425853", v: 2,});
this.pdfRef.current?.getDocument().addAnnotation([inkAnnotation]);Annotations can be customized (e.g. color, stroke width) before being added to the document.
Using the built-in signature user interface (UI)
Nutrient React Native SDK provides a built-in signature modal that opens when end users tap a signature field or select the signature tool. They can:
- Draw their signature using a touchscreen or stylus
- Attach an image of their scanned signature
- Type their name with customizable styles and fonts
Gating the signature user interface (UI)
Add the onShouldShowSignaturePad prop to intercept a tap on a signature widget before the SDK presents its signature UI. The presentation is suppressed until your app answers, which lets you run an approval check, substitute your own signing screen, or refuse the signature outright.
The callback receives a requestId, along with the fullyQualifiedName and pageIndex of the tapped widget:
const [pendingRequest, setPendingRequest] = useState(null);
const handleShouldShowSignaturePad = (event) => { const payload = event?.nativeEvent ?? event; setPendingRequest(payload);};
<NutrientView ref={pdfRef} document={DOCUMENT} onShouldShowSignaturePad={handleShouldShowSignaturePad} style={{ flex: 1 }}/>;Answer with showSignaturePad, passing the requestId you were given and whether to allow the presentation:
// Let the SDK present its signature UI after all.await pdfRef.current?.showSignaturePad(pendingRequest.requestId, true);
// Or drop the suppressed presentation entirely.await pdfRef.current?.showSignaturePad(pendingRequest.requestId, false);Interception is driven by the presence of the prop. Omit onShouldShowSignaturePad and the SDK presents its signature UI as usual.
Always answer a request. Until you call showSignaturePad for a given requestId, that signature presentation stays suppressed and tapping the widget again does nothing.
Dismissing an open signature UI
Use dismissSignaturePad to close a signature UI that’s already on screen, including one the SDK presented itself. It resolves to a Boolean reporting whether a signature UI was actually dismissed:
const dismissed = await pdfRef.current?.dismissSignaturePad();Replacing the signature UI with your own
Denying the request and writing the signature yourself lets you keep your own signing experience while still producing a normal signature annotation in the document.
Deny the presentation, find the widget’s bounding box, and add an ink annotation positioned inside it:
const signInApp = async (request, points) => { // The app is signing instead, so drop the suppressed presentation. await pdfRef.current?.showSignaturePad(request.requestId, false);
// Locate the tapped signature widget to get its bounding box. const widgets = await pdfRef.current ?.getDocument() .getAnnotationsForPage(request.pageIndex, Annotation.Type.WIDGET);
const widget = widgets?.find( (candidate) => candidate?.formElement?.fullyQualifiedFieldName === request.fullyQualifiedName, );
if (widget?.bbox == null) { return; }
await pdfRef.current?.getDocument().addAnnotations({ format: 'https://pspdfkit.com/instant-json/v1', annotations: [ { v: 1, type: 'pspdfkit/ink', pageIndex: request.pageIndex, bbox: widget.bbox, opacity: 1, lineWidth: 3, strokeColor: '#1E3A8A', isDrawnNaturally: false, isSignature: true, lines: { points: [points], intensities: [points.map(() => 0.5)], }, }, ], });};The points come from your own signing screen, in PDF page coordinates. Setting isSignature to true marks the annotation as a signature rather than an ordinary ink drawing.
Preventing signing
To stop a user signing a field, deny the request in onShouldShowSignaturePad:
const handleShouldShowSignaturePad = async (event) => { const payload = event?.nativeEvent ?? event; const allowed = await yourApprovalCheck(payload.fullyQualifiedName); await pdfRef.current?.showSignaturePad(payload.requestId, allowed);};Don’t use setFormFieldReadOnly to block signing. It’s portable for value fields, but not for signature widgets: On iOS, a locked signature field swallows the tap before the SDK asks to present anything, so onShouldShowSignaturePad never fires, while on Android, the callback still fires, and allowing it still opens the pad. Denying the request is the approach that behaves the same on both platforms.
Saving and managing electronic signatures on iOS and Android
Use Nutrient React Native SDK to enable end users to save and reuse electronic signatures in your app, specifically:
- Save signatures when they’re added to a document based on the
signatureSavingStrategysetting. Configure this to always save signatures, or allow end users to choose. - Retrieve stored signatures to enable end users to reuse them instead of creating a new one each time.
Using the built-in signature storage
By default, no signature storage is provided. However, it’s possible to enable a default built-in signature store using the signatureSavingStrategy property of the PDFConfiguration class:
<NutrientView ref={this.pdfRef} document={DOCUMENT} configuration={{ signatureSavingStrategy: "saveIfSelected", }} style={styles.pdfColor}/>Custom signature storage
For a custom storage solution, implement a class that conforms to the SignatureStore (iOS) or SignatureStorage (Android) protocol, which handles adding, removing, and retrieving signatures.
For detailed platform-specific implementations, refer to the following guides:
- How to bridge native iOS code to React Native
- How to fork the Nutrient React Native repository
- Save and store electronic signatures on iOS
- How to save and store electronic signatures on Android