Mischief

33 / Documents

Signature Pad

Sign with a pointer on a canvas, or type a name instead. Returns a PNG data URL or the typed text.

Signature

Draw with a pointer, or switch to typing.

Installation

Copy the source into your project, or keep it behind a package.

npx shadcn@latest add Tinkerers-Labs/mischief-ui/signature-pad
import { SignaturePad } from "mischief-ui/signature-pad"
Also installs
  • lucide-react

Or paste it in yourself. The source imports the shared cn helper from @/lib/utils, so point that at your own copy.

registry/default/signature-pad/signature-pad.tsx
"use client" import * as React from "react"import { Eraser, PenLine, Type } from "lucide-react"import { cn } from "@/lib/utils" export type SignatureMode = "draw" | "type" export type SignatureValue = {  mode: SignatureMode  dataUrl?: string  text?: string} 

Usage

export function Sign() {
  return <SignaturePad onChange={(value) => setSignature(value)} />
}

What you get back

onChange reports the whole signature or null when it is cleared. A drawn signature arrives as a PNG data URL; a typed one arrives as the text, leaving the rendering to you. The mode tells you which of the two you are holding, so you never have to guess from which field is set.

<SignaturePad
  onChange={(value) => {
    if (!value) return clear()
    if (value.mode === "draw") return save({ image: value.dataUrl })
    save({ typed: value.text })
  }}
/>

Store the typed variant as text rather than as a picture of text. It stays searchable, it survives a font change, and you can render it at whatever size the document needs.

Sharpness

The canvas is sized to the device pixel ratio and the drawing context scaled to match, so strokes are sharp on a retina screen instead of soft. That also means the exported PNG comes out at the device's resolution, not at the CSS size: on a 2x screen a 480 by 180 pad exports 960 by 360.

Size for that if the image is going into a printed document, and remember the export carries whatever penColor and lineWidth were set, on a transparent background.

API

mode, defaultMode"draw" | "type"The active method, controlled or uncontrolled.
onChange(value: SignatureValue | null) => voidRuns with the PNG data URL or typed text, and null once cleared.
penColor, lineWidthstring, numberStroke appearance.
heightnumberSigning area height in pixels. Defaults to 180.
typedFontFamilystringThe face used for a typed signature.
hintReactNodeGuidance shown under the signing area.

SignatureValue

mode"draw" | "type"Which kind of signature this is.
dataUrlstringPNG data URL, on a drawn signature.
textstringThe typed name, on a typed signature.

Accessibility

Drawing on a canvas cannot be done with a keyboard, so typing is a first-class method rather than a fallback, and the canvas says so in its accessible name. The method switch is a labelled group of toggle buttons. Clearing is disabled while there is nothing to clear. The canvas is redrawn at the device pixel ratio so a signature is not blurred on a high-density screen.