Library / SDK
szimek/signature_pad avatar
szimek/signature_pad

signature_pad: a canvas signature library for the browser, not a hardware pad

HTML5 canvas based smooth signature drawing

12,048 stars2,170 forksTypeScriptMIT

At a glance

What is it?
szimek/signature_pad is a dependency-free JavaScript library that turns a canvas element into a variable-width signature field. It is for developers embedding signatures in web forms, not for anyone shopping for a Topaz or Wacom tablet.
Who is it for?
Adopt signature_pad if you need a canvas signature field inside a web form and you are prepared to handle devicePixelRatio scaling yourself, because the README treats that as a tip rather than a built-in feature. Do not adopt it if you need a hardware capture device, a server-side verification service, or a component that manages its own canvas sizing.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem signature_pad solves is drawing, not capturing

A plain canvas element records pointer positions but draws them badly. Move the cursor quickly and you get a polyline with visible corners. Draw slowly and the line looks thin where a pen would press harder. signature_pad exists to close that gap in the browser: it takes pointer input on a canvas and renders it as a smooth stroke whose width varies with drawing speed. The README describes the technique as variable width Bézier curve interpolation, based on Square's Smoother Signatures post.

The audience is narrow and specific. This is for a developer who has a form asking for a signature and wants the result as an image or as point data, without pulling in a drawing framework. It is not a document signing product. There is no certificate, no audit trail, no identity check, no storage. The library hands you a data URL or an array of points and stops there. Everything about what that signature means legally or procedurally is outside its scope, and the README does not pretend otherwise.

How the Bézier interpolation and point pipeline actually work

The library is written in TypeScript, with src/signature_pad.ts declared as the source entry in package.json and the build emitting both a UMD bundle and an ES module. The published package exposes an exports map with separate import, require and default conditions, so a bundler picks dist/signature_pad.js for ESM and dist/signature_pad.umd.js for CommonJS.

Internally the model is a list of point groups. Each pointer movement becomes a point, and the library keeps a running velocity that is smoothed rather than replaced outright. The option velocityFilterWeight, defaulting to 0.7, controls how much the previous velocity counts toward the new one. That smoothed velocity drives the stroke width between minWidth (default 0.5) and maxWidth (default 2.5), which is why a fast flick draws thin and a slow drag draws thick.

Two options cut work before it reaches the renderer. throttle, defaulting to 16, draws the next point at most once per that many milliseconds, and minDistance, defaulting to 5, discards a point unless it is farther than that many pixels from the previous one. Both are lossy by design. Setting throttle to 0 turns throttling off, which the README explicitly documents. On a high refresh rate display, the default 16 ms throttle is the thing standing between you and a much larger point array, so raising it is a real trade of fidelity for data volume.

Installing signature_pad and drawing a first signature

The README gives two package manager routes and one script tag route. The npm command installs the latest release:

bash
npm install --save signature_pad

Yarn users get the equivalent command. For a page with no build step, the README shows a script tag pointing at the UMD minified build on jsDelivr, with a note to replace the version placeholder with the version you want:

html
<script src="https://cdn.jsdelivr.net/npm/signature_pad@[version]/dist/signature_pad.umd.min.js"></script>

Once loaded, the constructor takes a canvas element and an optional options object. The README's own example sets a thicker pen in a specific blue:

javascript
const canvas = document.querySelector("canvas");
const signaturePad = new SignaturePad(canvas, {
    minWidth: 5,
    maxWidth: 10,
    penColor: "rgb(66, 133, 244)"
});

The same options can be assigned after construction, since the README shows minWidth, maxWidth and penColor being set directly on the instance. To get the result out, call toDataURL for a PNG, pass "image/jpeg" for a JPEG, or call toSVG for an SVG string. If you want to restore a signature later, toData returns an array of point groups and fromData draws it back, with an option to skip clearing the existing canvas:

javascript
const data = signaturePad.toData();
signaturePad.fromData(data, { clear: false });

One detail matters before you ship. The README states that fromDataURL does not populate the internal data structure representing the drawn signature, and that after using it, toData will not work properly. If your flow loads an existing signature image and later tries to serialize the points, that path is broken by design, and the README says so rather than hiding it.

The high DPI problem is left to the caller

The most consequential limitation is not in the drawing code. It is in canvas sizing. The README's Tips and tricks section says that to handle low and high DPI screens correctly you have to take devicePixelRatio into account and scale the canvas accordingly, and that this scaling is also necessary to display signatures loaded through fromDataURL. It points at the demo source and an HTML5 Rocks tutorial for the technique.

That means the library will not do it for you. On a retina display, a canvas that is not scaled produces a signature that is soft or offset, and the failure appears only on some of your users' machines, which makes it expensive to discover late. The same applies to window resize: the README directs readers to the demo's app.js for tips on handling resize, which is a pointer rather than an implementation. If you are building a signature field that must survive rotation on a phone, you are writing that resize logic yourself.

A second boundary is the absence of undo and erase in the core API. The README lists an Erase feature and an Undo feature as separate jsFiddle demos rather than as methods. clear() wipes the whole canvas. If you need per-stroke undo, you are managing the point-group array from toData yourself and replaying it through fromData.

How signature_pad differs from a hardware capture device

Most search traffic around the phrase signature pad concerns physical hardware: Topaz and Wacom tablets, devices sold on Amazon, pads that plug into a PC and capture a pen on a dedicated surface. Those are different products solving a related but distinct problem. A hardware pad gives you a pressure-sensitive surface and, often, a signed capture device with its own drivers and SDK. signature_pad gives you none of that. It reads pointer events from whatever input the browser already has: a mouse, a trackpad, a finger, or a stylus on a touchscreen.

The practical difference shows up in the integration. With a hardware tablet you install a driver, call a vendor SDK, and often get a device-specific data format. With signature_pad you add an npm dependency, drop a canvas in a form, and get a data URL or a point array. There is no device to provision and no driver to deploy, but there is also no pressure data and no capture-hardware attestation. If your requirement is that the signature came from a specific piece of hardware, this library is the wrong layer entirely.

Against a full document-signing service the split is similar. Those services handle envelopes, signer identity and retention. signature_pad handles the drawing surface and the export. Teams often use both: this library for the field, a service for everything after.

Licence, releases and what an upgrade costs

The package is MIT licensed, and the repository carries a LICENSE file at the top level. For most teams that means the obligations are limited to keeping the copyright notice and permission text with the distribution, but the terms are short enough to read directly and this is not legal advice.

Release history is steady rather than quiet. v5.1.2 landed on 2025-11-16, v5.1.3 on 2025-12-03, and v5.1.4 on 2026-07-31, with the last push to the repository on 2026-09-13. The version numbers in that sequence are patch releases, which suggests a maintainer who is not sitting on the codebase. The repository is not archived.

The upgrade surface is small because the public API is small. The methods the README documents are toDataURL, toSVG, fromDataURL, toData, fromData, redraw, clear, isEmpty, off and on, plus the option properties. A method that returns a data URL and an array of points is not a large contract to keep stable. The realistic upgrade cost is in the build, not the API: package.json declares type module and an exports map with distinct import, require and default conditions, so a bundler or Node resolution change can affect which file you get. Verify that your build resolves dist/signature_pad.js for ESM rather than falling through to the UMD default before you trust an upgrade.

Events, cancellation and where the API stops

The library emits four events: beginStroke, endStroke, beforeUpdateStroke and afterUpdateStroke. They are registered with addEventListener, and the README shows a listener with a once option. beginStroke is the interesting one, because the README states it can be canceled with event.preventDefault(). That is the hook for gating input, for example refusing to start a stroke until a consent checkbox is ticked.

The event set is deliberately thin. There is no event for a completed signature, no debounce, no validation callback. If you want to enable a submit button only when something has been drawn, the documented tool is isEmpty(), called on your own schedule. If you want to know when the user stopped drawing, you build that from endStroke plus a timer. This is a library that draws and exports; the surrounding state machine is yours.

Editorial conclusion

Adopt signature_pad if you need a canvas signature field inside a web form and you are prepared to handle devicePixelRatio scaling yourself, because the README treats that as a tip rather than a built-in feature. Do not adopt it if you need a hardware capture device, a server-side verification service, or a component that manages its own canvas sizing. Before wiring it into a form, verify three things in your own build: that your bundler resolves the exports map to the right file, that your canvas sizing survives window resize on a high DPI display, and that fromDataURL is not being used in a path where toData is called later, since the README states the internal point structure is not populated by that method.

Frequently asked questions

What is signature_pad?

It is a JavaScript library for drawing smooth signatures on an HTML5 canvas, using variable width Bézier curve interpolation based on Square's Smoother Signatures post. It has no external dependencies and is published on npm as signature_pad under the MIT licence.

How do I install signature_pad?

The README gives npm install --save signature_pad, the equivalent yarn add signature_pad, or a script tag pointing at the UMD minified build on jsDelivr with the version placeholder replaced. The package ships both UMD and ES6 module builds.

Can I use signature_pad on a laptop or phone?

The README states it works in all modern desktop and mobile browsers, and the demo is described as working in both. Input comes from whatever the browser exposes, so a trackpad, mouse, finger or stylus all draw on the same canvas.

How do I set up signature_pad?

Create a canvas element, construct new SignaturePad(canvas) with an optional options object, and the pad binds its own event handlers. The README notes that off() unbinds all handlers and on() rebinds them if you need to detach the pad temporarily.

How do I use signature_pad in a web page?

The README's usage section shows selecting a canvas, constructing a SignaturePad on it, and then calling methods such as toDataURL to export a PNG, JPEG or SVG, or toData to get the point groups. Options like minWidth, maxWidth and penColor can be set at construction or assigned on the instance later.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. szimek/signature_pad on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/szimek-signature-pad.svg)](https://hysenlabs.com/projects/szimek-signature-pad)