This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/react-native/signatures.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise. Sign PDFs in React Native: Add electronic signatures in your app

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 user
  • StampAnnotation — 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 signatureSavingStrategy setting. 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: