Signature Pad
FormCanvas-based signature capture pad.
Preview
Usage
example.jsx
import { SignaturePad } from "@/components/ui/signature-pad";
export default function Example() {
return <SignaturePad />;
}Source Code
Copy this file into components/ui/signature-pad.jsx in your project.
signature-pad.jsx
"use client";
import { forwardRef, useRef, useEffect, useState } from "react";
import { cn } from "@/lib/utils";
const SignaturePad = forwardRef(({ className, onSignature, width = 400, height = 200, ...props }, ref) => {
const canvasRef = useRef(null);
const [drawing, setDrawing] = useState(false);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "currentColor";
ctx.lineWidth = 2;
ctx.lineCap = "round";
}, []);
const getPos = (e) => {
const rect = canvasRef.current.getBoundingClientRect();
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
return { x: clientX - rect.left, y: clientY - rect.top };
};
const start = (e) => {
setDrawing(true);
const ctx = canvasRef.current.getContext("2d");
const pos = getPos(e);
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
};
const draw = (e) => {
if (!drawing) return;
const ctx = canvasRef.current.getContext("2d");
const pos = getPos(e);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
};
const stop = () => {
setDrawing(false);
onSignature?.(canvasRef.current?.toDataURL());
};
const clear = () => {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
onSignature?.("");
};
return (
<div ref={ref} className={cn("inline-flex flex-col gap-2", className)} {...props}>
<canvas
ref={canvasRef}
width={width}
height={height}
className="rounded-md border border-input bg-background cursor-crosshair touch-none"
onMouseDown={start} onMouseMove={draw} onMouseUp={stop} onMouseLeave={stop}
onTouchStart={start} onTouchMove={draw} onTouchEnd={stop}
/>
<button type="button" onClick={clear} className="self-end text-xs text-muted-foreground hover:text-foreground cursor-pointer">Clear</button>
</div>
);
});
SignaturePad.displayName = "SignaturePad";
export { SignaturePad };
Quick Install
Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.
npm install clsx tailwind-merge