JavaScript 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 | Type | Description |
---|---|---|
name? | String | Represents the identifier for the signature pad. |
line? | Number | The size of each painted point. |
value? | Array of Arrays | 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. |
getValue | Function | Gets the value array. |
setValue | Function | Sets the internal state value. |
getImage | Function | Gets the image based on the value. |
Events
Event | Description |
---|---|
onchange? | When the value of the component changes |
onload? | When the component completes loading |
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";
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, { useRef } from 'react';
import Signature from '@lemonadejs/signature/dist/react';
export default function App() {
const signatureRef = useRef();
return (<>
<Signature
ref={signatureRef}
value={[]}
width={400}
height={200}
instructions={"Please sign this document"}
/>
</>);
}
<template>
<Signature ref="signature" :value="[]" :width="400" :height="200" instructions="Please sign this document" />
</template>
<script>
import Signature from '@lemonadejs/signature/dist/vue';
export default {
name: 'App',
components: {
Signature,
},
};
</script>
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";
function Component() {
const self = this;
self.change = function() {
console.log(JSON.stringify(self.signRef.value));
}
self.load = function() {
self.signRef.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
];
}
self.increase = function() {
self.signRef.width = 800
}
return `<>
<div class="signature">
<Signature
:ref="self.signRef"
:value="[]"
:onchange="self.change"
:width="500"
:height="200"
instructions="Please sign in the box above"
/>
</div><br>
<input type="button" value="Update width" onclick="self.increase" />
<input type="button" value="Update value" onclick="self.load" />
</>`;
}
import React, { useRef } from 'react';
import Signature from '@lemonadejs/signature/dist/react';
export default function App() {
const signatureRef = useRef();
const displayNewValue = function () {
console.log(JSON.stringify(signatureRef.current.value));
};
const increase = function () {
signatureRef.current.width = 800;
};
const load = function () {
signatureRef.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
];
};
return (<>
<Signature
ref={signatureRef}
value={[]}
width={500}
height={200}
instructions={"Please sign in the box above"}
onchange={displayNewValue}
/>
<input type="button" onClick={increase} value="Update Width" />
<input type="button" onClick={load} value="Update Value" />
</>);
}
<template>
<Signature
ref="signature"
:value="[]"
:width="500"
:height="200"
instructions="Please sign in the box above"
/>
<input type="button" @click="increase" value="Update Width" />
<input type="button" @click="load" value="Update Value" />
</template>
<script>
import Signature from '@lemonadejs/signature/dist/vue';
export default {
name: 'App',
components: {
Signature,
},
methods: {
increase() {
this.$refs.signature.current.width = 800
},
load() {
this.$refs.signature.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
]
},
displayNewValue() {
console.log(JSON.stringify(this.$refs.signature.current.value));
}
}
};
</script>
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="Save as image" id="getImage" />
<img id="image" class="image full-width" />
<script>
const root = document.getElementById("root")
const resetCanvas = document.getElementById("resetCanvas")
const getImage = document.getElementById("getImage")
// Call signature with the root element and the options object, saving its reference in a variable
const component = Signature(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 "@lemonadejs/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, { useRef } from 'react';
import Signature from '@lemonadejs/signature/dist/react';
export default function App() {
const signatureRef = useRef(null);
const imgRef = useRef(null);
const onGetImage = function () {
imgRef.current.src = signatureRef.current.getImage();
};
const reset = function () {
signatureRef.current.value = [];
};
return (<>
<Signature
ref={signatureRef}
value={[]}
width={500}
height={100}
instructions={"Please sign in the box above"}
/>
<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>
</>);
}
<template>
<Signature
ref="signature"
:value="[]"
:width="500"
:height="100"
instructions="Please sign in the box above"
/>
<input type="button" value="Reset" @click="reset" />
<input
type="button"
value="Download as image"
@click="onGetImage"
/>
<div>
<img ref="imgRef" className="image full-width" />
</div>
</template>
<script>
import Signature from '@lemonadejs/signature/dist/vue';
export default {
name: 'App',
components: {
Signature,
},
methods: {
onGetImage() {
this.$refs.imgRef.src = this.$refs.signature.current.getImage();
},
reset() {
this.$refs.signature.current.value = [];
}
}
};
</script>
Further references
Downloading Image from Base64
To initiate the download of an image from the signature component, you can employ a method akin to the previous example, with additional code for downloading the base64-encoded image.
Below is a sample code snippet that can serve as a foundation:
function handleDownload() {
// Retrieve the base64 string value from the signature component
const cleanBase64 = component.getImage().split(',')[1]
// Convert base64 to a blob
const byteCharacters = atob(cleanBase64);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], { type: 'application/octet-stream' });
// Create a download link
const downloadLink = document.createElement('a');
downloadLink.href = URL.createObjectURL(blob);
downloadLink.download = 'signature.png'; // Set the desired file name and extension
// Trigger the download
document.body.appendChild(downloadLink);
downloadLink.click();
// Remove the link from the page
document.body.removeChild(downloadLink);
}