Signature

A pad to sign with a finger or a stylus, handing back the strokes as JSON or SVG.

Open Source

Installation

Signature ships with the library — install it once, then import:

import { Signature } from "@delacour/react-native-ui/signature";

Or copy the source into your project, to own and edit it:

bunx delacour@latest add signature

Usage

app/index.tsx
import { Signature, type SignatureValue } from "@/components/ui/signature";
import { useState } from "react";
import { View } from "react-native";

export default function Example() {
  const [signature, setSignature] = useState<SignatureValue | null>(null);

  return (
    <View className="flex-1 justify-center p-4">
      <Signature guidelineLabel="Sign above the line" onValueChange={setSignature} />
    </View>
  );
}

Offer another way to sign

Not everyone can trace a path with a finger, so pass onRequestAlternative on every pad: it adds a "Can't sign? Type your name" link that hands off to a flow you own.

Type instead
const [isTyping, setIsTyping] = useState(false);

isTyping ? (
  <Field>
    <Field.Label>Type your full name</Field.Label>
    <Input autoComplete="name" placeholder="Full name" />
  </Field>
) : (
  <Signature onRequestAlternative={() => setIsTyping(true)} onValueChange={setSignature} />
);

Choosing the actions

Write the anatomy out to pick the toolbar's buttons; each is disabled while it would do nothing.

With the toolbar written out
<Signature>
  <Signature.Pad />
  <Signature.Toolbar>
    <Signature.Alternative />
    <Signature.Undo />
    <Signature.Redo />
    <Signature.Clear />
  </Signature.Toolbar>
</Signature>

In a form

A Field cascades isInvalid and isDisabled, and its label names the pad to a screen reader.

In a field
<Field isInvalid={submitted && !signature}>
  <Field.Label>Signature</Field.Label>
  <Signature onValueChange={setSignature} />
  <Field.Error>{submitted && !signature ? "Please sign to accept the delivery" : undefined}</Field.Error>
</Field>

The value

onValueChange fires when a finger lifts, never while it moves, with plain JSON — or null once the pad is empty.

Basic
Basic
type SignatureValue = {
  width: number;
  height: number;
  strokes: readonly (readonly { x: number; y: number; t?: number }[])[];
};

serializeSignature and parseSignature round-trip it through a string; a pad of another size re-fits it.

<Signature
  defaultValue={parseSignature(saved)}
  onValueChange={(value) => save(value ? serializeSignature(value) : null)}
/>

Exporting SVG and PNG

The ref's toSVG() returns a standalone SVG document, with literal colours and #000000 ink by default. toPNG() takes the same options plus scale and returns the same frame as a base64 PNG, transparent unless background is set.

const pad = useRef<SignatureHandle>(null);

<Signature ref={pad} />;

const svg = pad.current?.toSVG({ viewBox: "tight", padding: 8, background: "#ffffff" });
const png = pad.current?.toPNG({ viewBox: "tight", background: "#ffffff", scale: 3 });
const uri = `data:image/png;base64,${png}`;

toPaths() returns one path d per stroke instead, for drawing it elsewhere with react-native-svg. To draw a stroke with Skia, as the pad itself does, trace it into a path builder rather than parsing that string back:

import { Skia } from "react-native-skia";
import { traceStroke } from "@/components/ui/signature";

const builder = Skia.PathBuilder.Make();
traceStroke(stroke, builder);
const path = builder.detach();

Sizes and variants

sm, md and lg are pad heights of 120, 180 and 240 points, full fills its parent, and secondary is outlined.

<Signature size="sm" />
<Signature size="lg" variant="secondary" />
<View className="flex-1">
  <Signature size="full" />
</View>

Disabled and read-only

isReadOnly shows the drawing at full strength with no toolbar; isDisabled fades both and takes no touch.

Disabled and read-only
Disabled and read-only
<Signature defaultValue={signed} isReadOnly />

A ScrollView will not scroll from a drag that starts on the pad, which takes every touch at once so no downstroke is lost. Leave room around it to scroll from.

API Reference

Anatomy

PartWhat it is
SignatureOwns the strokes, the undo history, the axes and the ref
Signature.PadThe drawing surface — the gesture, the ink, the guideline and the accessibility surface
Signature.ToolbarThe row of actions under the pad. Hidden while read-only
Signature.UndoRemoves the last stroke
Signature.RedoRestores the last stroke undone
Signature.ClearRemoves every stroke, for good
Signature.AlternativeThe typed-name link, rendered only when onRequestAlternative is passed

Signature

Prop

Type

SignatureHandle

Prop

Type

SignatureExportOptions

Prop

Type

SignaturePngOptions

SignatureExportOptions, plus:

Prop

Type

Signature.Undo, Signature.Redo, Signature.Clear, Signature.Alternative

Each takes Button's props, minus onPress. children replaces the glyph with a label.

On this page