Skip to main content
0.49.0
View Zag.js on Github
Join the Discord server

Signature Pad

The signature pad component allows users to draw handwritten signatures using touch or pointer devices. The signature can be saved as an image or cleared.

Features

  • Draw signatures using touch or pointer devices.
  • Save the signature as an image.
  • Clear the signature.

Installation

To use the signature pad machine in your project, run the following command in your command line:

npm install @zag-js/signature-pad @zag-js/react # or yarn add @zag-js/signature-pad @zag-js/react

This command will install the framework agnostic signature pad logic and the reactive utilities for your framework of choice.

Anatomy

To set up the signature pad correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Usage

First, import the signature pad package into your project

import * as signaturePad from "@zag-js/signature-pad"

The signature pad package exports two key functions:

  • machine — The state machine logic for the signature pad widget.
  • connect — The function that translates the machine's state to JSX attributes and event handlers.

Next, import the required hooks and functions for your framework and use the signature pad machine in your project 🔥

import { normalizeProps, useMachine } from "@zag-js/react" import * as signaturePad from "@zag-js/signature-pad" import { useId, useState } from "react" export function SignaturePad() { const [state, send] = useMachine( signaturePad.machine({ id: useId(), }), ) const api = signaturePad.connect(state, send, normalizeProps) return ( <div {...api.rootProps}> <label {...api.labelProps}>Signature Pad</label> <div {...api.controlProps}> <svg {...api.segmentProps}> {api.paths.map((path, i) => ( <path key={i} {...api.getSegmentPathProps({ path })} /> ))} {api.currentPath && ( <path {...api.getSegmentPathProps({ path: api.currentPath })} /> )} </svg> <button {...api.clearTriggerProps}>X</button> <div {...api.guideProps} /> </div> </div> ) }

Listening to drawing events

The signature pad component emits the following events:

  • onDraw: Emitted when the user is drawing the signature.
  • onDrawEnd: Emitted when the user stops drawing the signature.
const [state, send] = useMachine( signature.machine({ onDraw(details) { // details => { path: string[] } console.log("Drawing signature", details) }, onDrawEnd(details) { // details => { path: string[], toDataURL: () => string } console.log("Signature drawn", details) }, }), )

Clearing the signature

To clear the signature, use the api.clear(), or render the clear trigger button.

<button onClick={() => api.clear()}>Clear</button>

Rendering an image preview

Use the api.getDataUrl() method to get the signature as a data URL and render it as an image.

You can also leverage the onDrawEnd event to get the signature data URL.

const [state, send] = useMachine( signature.machine({ onDrawEnd(details) { details.getDataUrl("image/png").then((url) => { // set the image URL in local state setImageURL(url) }) }, }), )

Next, render the image preview using the URL.

<img src={imageURL} alt="Signature" />

Changing the stroke color

To change the stroke color, set the drawing.fill option to a valid CSS color.

Note: You can't use a css variable as the stroke color.

const [state, send] = useMachine( signature.machine({ drawing: { fill: "red", }, }), )

Changing the stroke width

To change the stroke width, set the drawing.size option to a number.

const [state, send] = useMachine( signature.machine({ drawing: { size: 5, }, }), )

Simulating pressure sensitivity

Pressure sensitivity is disabled by default. To enable it, set the drawing.simulatePressure option to true.

const [state, send] = useMachine( signature.machine({ drawing: { simulatePressure: true, }, }), )

Usage in forms

To use the signature pad in a form, set the name context property.

const [state, send] = useMachine( signature.machine({ name: "signature", }), )

Then, render the hidden input element using api.getHiddenInputProps.

<input {...api.getHiddenInputProps({ value: imageURL })} />

Disabling the signature pad

Set the disabled context property to true to disable the signature pad.

const [state, send] = useMachine( signature.machine({ disabled: true, }), )

Making the signature pad read-only

Set the readOnly context property to true to make the signature pad read-only.

const [state, send] = useMachine( signature.machine({ readOnly: true, }), )

Methods and Properties

The signature pad api exposes the following methods and properties:

Machine Context

The signature pad machine exposes the following context properties:

  • idsPartial<{ root: string; control: string; hiddenInput: string; }>The ids of the signature pad elements. Useful for composition.
  • onDraw(details: DrawDetails) => voidCallback when the signature pad is drawing.
  • onDrawEnd(details: DrawEndDetails) => voidCallback when the signature pad is done drawing.
  • drawingDrawingOptionsThe drawing options.
  • disabledbooleanWhether the signature pad is disabled.
  • readOnlybooleanWhether the signature pad is read-only.
  • namestringThe name of the signature pad. Useful for form submission.
  • dir"ltr" | "rtl"The document's text/writing direction.
  • idstringThe unique identifier of the machine.
  • getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The signature pad api exposes the following methods:

  • emptybooleanWhether the signature pad is empty.
  • drawingbooleanWhether the user is currently drawing.
  • currentPathstringThe current path being drawn.
  • pathsstring[]The paths of the signature pad.
  • getDataUrl(type: DataUrlType, quality?: number) => Promise<string>Returns the data URL of the signature pad.
  • clear() => voidClears the signature pad.

Edit this page on GitHub

On this page