---
title: "JavaScript Signature Pad"
description: "The LemonadeJS Signature Pad block for JavaScript: Signature drawing pad. Contract-verified, framework-agnostic, zero dependencies, with a live example."
source: https://lemonadejs.com/docs/plugins/signature/
---

<link rel="stylesheet" href="/v6/signature.css">

# JavaScript Signature Pad

`@lemonadejs/signature` · ✓ 23 contract checks · framework-agnostic · zero dependencies

`<Signature />` — canvas signature pad, ported from the v5 plugin

Full behavioral parity with v5: pointer drawing (mouse + touch), the v5
value format (a flat list of [x, y] points with '1' separators between
strokes), line thickness, instructions text, disabled, and the full
replay algorithm (commit): clear + redraw the whole value as one path —
including the v5 quirk where a click stroke becomes a round dot.

v5 → v6 mapping: value (two-way) → bind; value (initial) stays value;
line/width/height/instructions/disabled unchanged; onchange/onload
unchanged (onchange now receives the value, not the instance);
getValue/setValue/getImage move to the api surface (props.ref), plus
clear() = setValue([]). New: color (v5 hardcoded #000), name (renders
a hidden input so the pad participates in forms — v5 only patched .val()
onto the canvas), and clearlabel (renders a real, keyboard-operable
clear `<button>` — WCAG 2.1.1: clearing must not require a pointer).

Accessibility: drawing is a path-of-movement input (WCAG 2.1.1
essential-exception territory) — the canvas is exposed as role="img"
("Signature pad") and the host application should offer keyboard users
an alternative (e.g. a typed signature) alongside the pad.

jsdom has no canvas: a null 2d context downgrades the pad to a no-op.

## Example

<!--example-->

```js
import { html } from 'lemonadejs';
import Signature from '@lemonadejs/signature';

const App = (props, { state }) => {
    const strokes = state([]);
    const image = state('');
    let pad;

    return html`<div>
        <${Signature} bind="${strokes}" width="400" height="160" color="#1d4ed8"
            instructions="Sign here to accept the delivery" ref="${(api) => (pad = api)}" />
        <p>
            <button onclick="${() => { pad.clear(); image.value = ''; }}">Clear</button>
            <button onclick="${() => (image.value = pad.getImage())}">Export PNG</button>
            ${() => (strokes.value.length ? ' Signature captured (' + strokes.value.length + ' points)' : ' Waiting for a signature')}
        </p>
        ${() => (image.value ? html`<img src="${image.value}" alt="Signature" style="border:1px solid #ddd" />` : '')}
    </div>`;
};
```

## Installation

```bash
npm install @lemonadejs/signature
```

```js
import Signature from '@lemonadejs/signature';
import '@lemonadejs/signature/style.css';
```

Three deployment forms, one component:

```js
html`<${Signature} />`                       // by value (no registration)
setComponents({ Signature });               // then <Signature /> by name anywhere
createWebComponent(Signature);              // <lm-signature> in plain HTML/any framework
```

## Props

Every declared prop arrives as a **live state** — pass a value for a snapshot or a
state for a two-way live wire. Attribute strings are coerced to the declared type.

| Prop | Type | Default | Description |
|---|---|---|---|
| `bind` | array | — | Two-way bound value. `.set()` fires `onchange`; plain assignment is silent. two-way stroke data (v5: value) |
| `value` | array | — | initial strokes when unbound |
| `width` | number | `0` | canvas width (0: browser default) |
| `height` | number | `0` | canvas height (0: browser default) |
| `line` | number | `0` | stroke thickness, 3 when unset (v5) |
| `color` | string | `''` | stroke color, #000 when unset (v5 fixed) |
| `name` | string | `''` | form field name (hidden input, JSON value) |
| `instructions` | string | `''` | helper text under the canvas |
| `clearlabel` | string | `''` | when set, renders a keyboard-operable clear `<button>` |
| `disabled` | boolean | `false` | blocks drawing |

## Events

All event names are lowercase (the platform convention — LJS-305 warns otherwise).

- `onchange` — fires on stroke end, setValue and clear
- `onload` — fires once the canvas is ready (v5)

## API

```js
import { ref } from 'lemonadejs';
const signature = ref();
html`<${Signature} ref="${signature}" />`;
// signature.current.getValue(...)  ·  signature.current.setValue(...)  ·  signature.current.getImage(...)  ·  signature.current.clear(...)
```

- `getValue()`
- `setValue()`
- `getImage()`
- `clear()`

## Styling

All classes follow the `lm-signature-*` convention; visual variants are `data-*`
attributes on the root. Override freely — there is no styling engine to fight.

## Contract

The machine-readable schema ships with the package:

```js
import contract from '@lemonadejs/signature/contract.json';
```

`verify.json` carries the conformance proof produced by `verify(Signature)`.

Looking for the v5 plugin? See the [archived v5 documentation](/docs/v5/plugins/).