shadcn.io is not affiliated with official shadcn/ui
Shadcn Signature Pad for React and Tailwind
Capture hand-drawn signatures.
Installation
bunx --bun shadcn@latest add https://kit.dev/r/signature-pad.jsonpnpm dlx shadcn@latest add https://kit.dev/r/signature-pad.jsonnpx shadcn@latest add https://kit.dev/r/signature-pad.jsonyarn shadcn@latest add https://kit.dev/r/signature-pad.json<Step>This component depends on Button. Install it first if you haven't already.</Step>
Install the following dependencies:
bun add @ark-ui/react lucide-reactpnpm add @ark-ui/react lucide-reactnpm install @ark-ui/react lucide-reactyarn add @ark-ui/react lucide-reactCopy and paste the following code into your project.
"use client";
import {
SignaturePad as ArkSignaturePad,
useSignaturePadContext,
} from "@ark-ui/react/signature-pad";
import { RotateCcw } from "lucide-react";
import type React from "react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
export const useSignaturePad = useSignaturePadContext;
export const SignaturePad = (
props: React.ComponentProps<typeof ArkSignaturePad.Root>
) => {
const { className, ...rest } = props;
return (
<ArkSignaturePad.Root
className={cn(
"h-40 min-h-40 w-full",
"flex flex-col gap-1.5",
"data-disabled:opacity-64 data-disabled:grayscale",
className
)}
data-slot="signature-pad"
{...rest}
>
<SignaturePadControl>
<SignaturePadSegment />
<SignaturePadClear />
<SignaturePadGuide />
</SignaturePadControl>
</ArkSignaturePad.Root>
);
};
const SignaturePadControl = (
props: React.ComponentProps<typeof ArkSignaturePad.Control>
) => {
const { className, ...rest } = props;
return (
<ArkSignaturePad.Control
className={cn(
"relative",
"size-full min-h-0 min-w-0",
"flex flex-col",
"bg-muted/64",
"rounded-xl border shadow-xs/5",
"data-disabled:cursor-not-allowed",
className
)}
data-slot="signature-pad-control"
{...rest}
/>
);
};
const SignaturePadSegment = (
props: React.ComponentProps<typeof ArkSignaturePad.Segment>
) => {
const { className, ...rest } = props;
return (
<ArkSignaturePad.Segment
className={cn(
"size-full",
"min-h-0",
"fill-foreground",
"touch-none",
className
)}
data-slot="signature-pad-segment"
{...rest}
/>
);
};
const SignaturePadClear = (
props: React.ComponentProps<typeof ArkSignaturePad.ClearTrigger>
) => {
const { className, ...rest } = props;
return (
<ArkSignaturePad.ClearTrigger
asChild
className={cn(
"absolute inset-e-2 top-2",
"bg-muted",
"text-muted-foreground",
className
)}
data-slot="signature-pad-clear"
{...rest}
>
<Button size="icon-md" variant="ghost">
<RotateCcw />
</Button>
</ArkSignaturePad.ClearTrigger>
);
};
const SignaturePadGuide = (
props: React.ComponentProps<typeof ArkSignaturePad.Guide>
) => {
const { className, ...rest } = props;
return (
<ArkSignaturePad.Guide
className={cn(
"absolute inset-x-6 bottom-6",
"border-input border-b-2 border-dashed",
"pointer-events-none",
className
)}
data-slot="signature-pad-guide"
{...rest}
/>
);
};Update the import paths to match your project setup.
Usage
import { SignaturePad } from "@/components/ui/signature-pad";<SignaturePad />Examples
Image preview
Use the onDrawEnd callback to capture the signature as an image.
The callback receives the getDataUrl(type) method that returns a promise that resolves to a data URL.
With field
Wrap the signature pad in a Field with FieldLabel and FieldHelper for accessible form integration.
API Reference
SignaturePad
Root component. Canvas for drawing signatures. Manages strokes and export.
| Prop | Type | Default |
|---|---|---|
disabled | boolean | false |
required | boolean | false |
readOnly | boolean | false |
name | string | - |
onDraw | (details: DrawDetails) => void | - |
onDrawEnd | (details: DrawEndDetails) => void | - |
className | string | - |
For a complete list of props, see the Ark UI documentation.