---
title: "Sign PDFs in React Native: Add electronic signatures in your app"
canonical_url: "https://www.nutrient.io/guides/react-native/signatures/"
md_url: "https://www.nutrient.io/guides/react-native/signatures.md"
last_updated: "2026-08-14T00:00:00.000Z"
description: "Enhance your React Native application by enabling users to sign PDFs. Learn how to integrate electronic signatures seamlessly with step-by-step guidance."
---

# 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 user

- `StampAnnotation` — For signatures attached as images

For example, to create an ink signature, use the following code in your React Native component:

```javascript

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:

```jsx

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:

```js

// 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:

```js

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:

```js

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`:

```js

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`](https://www.nutrient.io/guides/react-native/forms/fill-form-fields/disable-editing/#locking-a-single-form-field) 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`](https://www.nutrient.io/api/react-native/PDFConfiguration.html) 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:

```javascript

<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](https://www.nutrient.io/api/ios/documentation/pspdfkitui/signaturestore)) or `SignatureStorage` ([Android](https://www.nutrient.io/api/android/nutrient/com.pspdfkit.signatures.storage/-signature-storage/)) 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](https://www.nutrient.io/blog/how-to-bridge-native-ios-code-to-react-native/)

- [How to fork the Nutrient React Native repository](https://www.nutrient.io/blog/react-native-repo-forking-guide/)

- [Save and store electronic signatures on iOS](https://www.nutrient.io/guides/ios/signatures/signature-storage.md)

- [How to save and store electronic signatures on Android](https://www.nutrient.io/guides/android/signatures/signature-storage.md)
---

## Related pages

- [React Native PDF library](/guides/react-native.md)
- [Agent skill](/guides/react-native/agent-skill.md)
- [AI Assistant on React Native](/guides/react-native/ai-assistant.md)
- [Changelog for React Native](/guides/react-native/changelog.md)
- [Explore powerful demos of the React Native PDF library](/guides/react-native/demo.md)
- [Download our React Native library](/guides/react-native/downloads.md)
- [Edit PDFs in React Native](/guides/react-native/editor.md)
- [React Native guides: Integrate our PDF library](/guides/react-native/intro.md)
- [Knowledge base](/guides/react-native/kb.md)
- [Upgrade and migration guides](/guides/react-native/upgrade.md)

