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.
"use client"
import { SignaturePad } from "mischief-ui/signature-pad"
export function SignaturePadDemo() {
return <SignaturePad className="w-full max-w-md" height={150} />
}Installation
Copy the source into your project, or keep it behind a package.
npx shadcn@latest add Tinkerers-Labs/mischief-ui/signature-padimport { SignaturePad } from "mischief-ui/signature-pad"Or paste it in yourself. The source imports the shared cn helper from @/lib/utils, so point that at your own copy.
"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.