Signature Field Form Development
Signature field for handwritten signature used in legal documents, acceptance certificates, online contracts. Implementation looks simple but has nuances: different devices, different storage formats, legal significance.
Use Cases
- Contract signing and agreements directly in browser
- Work completion certificates in CRM/ERP
- Personal data processing agreement with proof
- Medical forms, insurance claims
- Courier apps (delivery confirmation)
How It Works Technically
Signature drawn on <canvas> element. Event handlers track mousedown/mousemove/mouseup on desktop and touchstart/touchmove/touchend on mobile. Final image exported via canvas.toDataURL('image/png') or converted to SVG path for scalability.
class SignaturePad {
constructor(canvas) {
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.points = [];
this.isDrawing = false;
this._setupEvents();
this._setupCanvas();
}
_setupCanvas() {
// HiDPI support
const ratio = window.devicePixelRatio || 1;
const rect = this.canvas.getBoundingClientRect();
this.canvas.width = rect.width * ratio;
this.canvas.height = rect.height * ratio;
this.ctx.scale(ratio, ratio);
this.ctx.strokeStyle = '#1a1a1a';
this.ctx.lineWidth = 2;
this.ctx.lineCap = 'round';
this.ctx.lineJoin = 'round';
}
_getPos(e) {
const rect = this.canvas.getBoundingClientRect();
const src = e.touches ? e.touches[0] : e;
return {
x: src.clientX - rect.left,
y: src.clientY - rect.top,
};
}
_setupEvents() {
this.canvas.addEventListener('mousedown', (e) => this._start(e));
this.canvas.addEventListener('mousemove', (e) => this._draw(e));
this.canvas.addEventListener('mouseup', () => this._end());
this.canvas.addEventListener('touchstart', (e) => { e.preventDefault(); this._start(e); }, { passive: false });
this.canvas.addEventListener('touchmove', (e) => { e.preventDefault(); this._draw(e); }, { passive: false });
this.canvas.addEventListener('touchend', () => this._end());
}
_start(e) {
this.isDrawing = true;
const pos = this._getPos(e);
this.ctx.beginPath();
this.ctx.moveTo(pos.x, pos.y);
this.points.push({ x: pos.x, y: pos.y, type: 'start' });
}
_draw(e) {
if (!this.isDrawing) return;
const pos = this._getPos(e);
this.ctx.lineTo(pos.x, pos.y);
this.ctx.stroke();
this.points.push({ x: pos.x, y: pos.y, type: 'draw' });
}
_end() {
this.isDrawing = false;
}
isEmpty() {
const data = this.ctx.getImageData(0, 0, this.canvas.width, this.canvas.height).data;
return !data.some((v, i) => i % 4 === 3 && v > 0);
}
toDataURL(type = 'image/png') {
return this.canvas.toDataURL(type);
}
clear() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.points = [];
}
}
Ready-Made Libraries
If no point building from scratch — signature_pad from Szimek (MIT, ~4 KB gzip). Supports Bezier curve smoothing, SVG export, signature recovery from data.
import SignaturePad from 'signature_pad';
const pad = new SignaturePad(document.getElementById('sig-canvas'), {
minWidth: 0.5,
maxWidth: 2.5,
penColor: '#000',
backgroundColor: 'rgba(0,0,0,0)', // transparent background for PNG
});
// Save
const dataURL = pad.toDataURL('image/svg+xml');
// Restore
pad.fromData(savedPointsArray);
Storage Formats
| Format | Pros | Cons |
|---|---|---|
| PNG (base64) | Simple, compatibility | Large size, doesn't scale |
| SVG | Scales, editable | Can be forged |
| JSON (points) | Full recovery, minimal data | Requires rendering to display |
| PDF (embedded) | Legally significant | More complex implementation |
For legally significant documents — store JSON with points + metadata (timestamp, IP, user-agent, document hash).
Embedding in PDF
For generating signed PDFs use pdf-lib (Node.js/browser):
import { PDFDocument } from 'pdf-lib';
async function embedSignature(pdfBytes, signatureDataURL) {
const pdfDoc = await PDFDocument.load(pdfBytes);
const pages = pdfDoc.getPages();
const page = pages[pages.length - 1];
const pngBytes = await fetch(signatureDataURL).then(r => r.arrayBuffer());
const img = await pdfDoc.embedPng(pngBytes);
page.drawImage(img, {
x: 50,
y: 50,
width: 200,
height: 80,
});
return await pdfDoc.save();
}
Mobile Devices
On touchscreen need to block scroll while drawing (touch-action: none on canvas), otherwise page scrolls instead of drawing. Apple Pencil and styli work through same Touch Events, but touchForce only available in Safari.
Timeframe
Basic signature field with clear, validate and save PNG — 2–3 working days. PDF generation integration, metadata storage and signature recovery — 4–6 days.







