Signature Pad

Pico Library

This library has less than 2 KBytes

The LemonadeJS JavaScript Signature Pad is a lightweight, reactive component that facilitates signature capture in web applications. Compatible with Vanilla, React, Vue, and Angular frameworks, it provides a canvas for capturing user signatures using mouse or touch input. With built-in methods for loading and retrieving signatures, developers can effortlessly build solutions that empower users to sign documents and securely store their signatures.

Documentation

Installation

npm install @lemonadejs/signature

Attributes

Attribute Description
value?: Array The value represents the painted point's position.
width?: Number The width of the signature pad.
height?: Number The height of the signature pad.
instructions?: String The instruction text. It appears at the bottom of the signature pad.
line?: Number The size of each painted point.
disabled?: Boolean Signature is disabled if true.

Methods

Method Description
getValue: function Gets the value array instance.getValue() => number[][]
setValue: function Sets the internal state value instance.setValue(value: number[][]) => void
getImage: function Gets the image based on the value instance.getImage() => string

Events

Event Description
onchange?: Function When the value of the component changes onchange(value: object) => void
onload?: Function When the component completes loading onload(value: object) => void

Codesandbox example

See this example on codesandbox.

Examples

Basic example

Basic example to show how to embed the LemonadeJS signature pad on your components.

<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/signature/dist/index.min.js"></script>
<div id="root"></div>
<script>
// Get the element to render signature component inside
const root = document.getElementById("root");
// Call signature with the root element and the options object
Signature(root, {
    value: [],
    width: 400,
    height: 200,
    instructions: "Please sign this document"
});
</script>
</html>
import lemonade from "lemonadejs";
import Signature from "@lemonadejs/signature";

// Register signature component across the application
lemonade.setComponents({ Signature });

export default function Component() {
    const self = this;
    self.width = 400;
    self.height = 200;
    self.value = [];
    return `<Signature
        value="{{self.value}}"
        width="{{self.width}}"
        height="{{self.height}}"
        instructions="Please sign this document" />`;
}
import React, { useEffect, useRef } from "react";
import Signature from "@lemonadejs/signature";

export default function Component() {
    const componentRef = useRef(null);

    useEffect(() => {
        if (!componentRef.current.innerText) {
            Signature(componentRef.current, {
                width: 400,
                height: 200,
                value: [],
                instructions: "Please sign this document"
            });
        }
    }, []);

    return <div ref={componentRef}></div>;
}

Programmatic changes

The following example implement some programmatic changes in the JavaScript signature component.

<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/signature/dist/index.min.js"></script>

<div id="root"></div>

<input type="button" value="Update width" id="updateWidth" />
<input type="button" value="Update value" id="updateValue" />

<script>
// Call signature with the root element and the options object, saving its reference in a variable
const component = Signature(document.getElementById("root"), {
    width: 500,
    height: 200,
    value: [],
    onchange: (o) => {
        console.log(JSON.stringify(o.value));
    }
});

// Changes the value of the signature instance
updateValue.addEventListener("click", () => {
    component.value = [
        [139,41],[139,45],[139,51],[139,56],[138,61],[138,65],[137,67],[137,69],[137,70],
        [137,71],[138,71],[142,66],[154,56],[171,45],[194,32],[220,21],[247,15],[270,10],
        [282,10],[292,11],[297,14],[297,15],[297,18],[297,20],[297,24],[297,27],[297,30],
        [297,33],[297,34],[297,35],[298,35],[299,36],[300,37],[302,37],1
    ];
});

updateWidth.addEventListener("click", () => {
    component.width = 800;
});
</script>
</html>
import lemonade from "lemonadejs";
import Signature from "@lemonadejs/signature";

// Register signature component across the application
lemonade.setComponents({ Signature });

function Component() {
    const self = this;
    self.width = 500;
    self.height = 200;
    self.value = [];

    self.change = function() {
        console.log(JSON.stringify(self.value));
    }

    self.load = function() {
        self.value = [
            [139,41],[139,45],[139,51],[139,56],[138,61],[138,65],[137,67],[137,69],[137,70],
            [137,71],[138,71],[142,66],[154,56],[171,45],[194,32],[220,21],[247,15],[270,10],
            [282,10],[292,11],[297,14],[297,15],[297,18],[297,20],[297,24],[297,27],[297,30],
            [297,33],[297,34],[297,35],[298,35],[299,36],[300,37],[302,37],1
        ];
    }

    return `<>
        <div class="signature">
            <Signature value="{{self.value}}"
               onchange="{{self.change}}"
               width="{{self.width}}"
               height="{{self.height}}"
               instructions="Please sign in the box above" />
        </div><br>
        <input type="button" value="Update width" onclick="self.width = 800" />
        <input type="button" value="Update value" onclick="self.load()"  />
    </>`;
}
import React, { useEffect, useRef } from "react";
import Signature from "@lemonadejs/signature";
    
export default function Component() {
    const divRef = useRef(null);
    const componentRef = useRef(null);

    const change = function () {
        console.log(JSON.stringify(componentRef.current.value));
    };

    const increase = function () {
        componentRef.current.width = 800;
    };

    const load = function () {
        componentRef.current.value = [
            [139,41],[139,45],[139,51],[139,56],[138,61],[138,65],[137,67],[137,69],[137,70],
            [137,71],[138,71],[142,66],[154,56],[171,45],[194,32],[220,21],[247,15],[270,10],
            [282,10],[292,11],[297,14],[297,15],[297,18],[297,20],[297,24],[297,27],[297,30],
            [297,33],[297,34],[297,35],[298,35],[299,36],[300,37],[302,37],1
        ];
    };

    useEffect(() => {
        if (!componentRef.current) {
            componentRef.current = Signature(divRef.current, {
                width: 500,
                height: 200,
                value: [],
                instructions: "Please sign in the box above",
                onchange: change
            });
        }
    }, []);

    return (
        <>
            <div ref={divRef}></div>
            <input type="button" value="Update width" onClick={() => increase()} />
            <input type="button" value="Update value" onClick={() => load()} />
        </>
    );
}

Methods

Exporting the signature as image base64.

<html>
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@lemonadejs/signature/dist/index.min.js"></script>

<div id='root'></div>
<input type="button" value="Reset" id="resetCanvas" />
<input type="button" value="Download as image" id="getImage" />
<img id="image" class="image full-width" />

<script>
// Call signature with the root element and the options object, saving its reference in a variable
const component = Signature(document.getElementById("root"), {
    width: 500,
    height: 100,
    instructions: "Please sign in the box above"
});

resetCanvas.addEventListener("click", () => {
    component.value = [];
});

getImage.addEventListener("click", () => {
    getImage.nextElementSibling.src = component.getImage();
});
</script>
</html>
import lemonade from "lemonadejs";
import Signature from "@lemonadejs/signature";

// Register signature component across the application
lemonade.setComponents({ Signature });

function Component() {
    const self = this;
    self.width = 500;
    self.height = 100;
    self.value = [];

    self.onGetImage = function() {
        self.image.src = self.component.getImage();
    };

    return `<>
        <div class="signature">
                <Signature :ref="self.component" value="{{self.value}}"
                    width="{{self.width}}"
                    height="{{self.height}}"
                    instructions="Please sign in the box above" />
        </div><br>
        <input type="button" value="Reset" onclick="self.value = []" />
        <input type="button" value="Download as image" onclick="self.onGetImage()" />
        <div>
            <img :ref="self.image" class="image full-width"/>
        </div>
    </>`;
}
import React, { useEffect, useRef } from "react";
import Signature from "@lemonadejs/signature";

export default function Component() {
    const divRef = useRef(null);
    const componentRef = useRef(null);
    const imgRef = useRef(null);

    const onGetImage = function () {
        imgRef.current.src = componentRef.current.getImage();
    };

    const reset = function () {
        componentRef.current.value = [];
    };

    useEffect(() => {
        if (!componentRef.current) {
            componentRef.current = Signature(divRef.current, {
                width: 500,
                height: 100,
                value: [],
                instructions: "Please sign in the box above"
            });
        }
    }, []);

    return (
        <>
            <div ref={divRef}></div>
            <input type="button" value="Reset" onClick={() => reset()} />
            <input
                type="button"
                value="Download as image"
                onClick={() => onGetImage()}
            />
            <div>
                <img ref={imgRef} className="image full-width" />
            </div>
        </>
    );
}

CSS for this section

.signature {
    border: 1px dashed #ccc;
    display: inline-block;
    text-align: center;
    margin-bottom: 10px;
}