# Signature Pad
A pure HTML and vanilla JS implementation of Zag JS 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.
# Anatomy
The Signature Pad component consists of the following data parts:
root, label, hidden-input, control, segment, clear-trigger, guide
<div
id="signature-anatomy"
class="signature-pad signature-pad-js"
data-on-draw-end="save-signature"
>
<div data-part="root">
<label data-part="label">Signature Pad</label>
<input data-part="hidden-input" />
<div data-part="control">
<svg data-part="segment"></svg>
<button data-part="clear-trigger">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"
/>
</svg>
</button>
<div data-part="guide"></div>
</div>
<div data-part="preview"></div>
</div>
</div>
document
.getElementById("signature-anatomy")
?.addEventListener("save-signature", async (event) => {
const details = (event as CustomEvent).detail;
console.log(details);
const dataUrl = await details.getDataUrl("image/png");
const preview = document.querySelector<HTMLElement>(
'[data-part="preview"]',
);
console.log(preview);
console.log(dataUrl);
if (!preview || !dataUrl) return;
preview.innerHTML = `
<img src="${dataUrl}" alt="Signature preview" />
<button class="button button--sm button--accent" id="download-signature">Save Signature</button>
`;
const downloadBtn = document.getElementById("download-signature");
downloadBtn?.addEventListener("click", () => {
const link = document.createElement("a");
link.href = dataUrl;
link.download = "signature.png";
link.click();
});
console.log("Signature preview populated with save button.");
});
# Data attributes
Each signature pad can be set with different settings with the following data-attribute.
<div
class="signature-pad signature-pad-js"
data-fill="red"
data-simulate-pressure="true"
data-size="6"
>
<div data-part="root">
<label data-part="label">Signature Pad</label>
<input data-part="hidden-input" />
<div data-part="control">
<svg data-part="segment"></svg>
<button data-part="clear-trigger">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"
/>
</svg>
</button>
<div data-part="guide"></div>
</div>
</div>
</div>
id
Type: string
Description: Unique id of the signature pad. Default generated if none is provided.
data-dir
Type: string
Description: The orientation of the signature pad. Can be ltr or rtl.
data-name
Type: string
Description: The name of the signature pad useful for form submission.
data-disabled
Type: boolean
Description: Whether the signature pad is disabled.
data-required
Type: boolean
Description: Whether the signature pad is required.
data-read-only
Type: boolean
Description: Whether the signature pad is read-only.
data-default-paths
Type: string[]
Description: Default signature paths (uncontrolled).
data-paths
Type: string[]
Description: Controlled signature paths.
data-fill
Type: string
Description: Stroke color of the signature.
data-size
Type: number
Description: Stroke size of the signature.
data-simulate-pressure
Type: boolean
Description: Whether to simulate pressure in stroke drawing.
# Event Callbacks
Each signature pad component can receive callbacks that can be used to respond to user interaction with custom behavior.
You must add a custom id for the signature pad and a event listener for your event name
document
.getElementById("my-signature-pad")
?.addEventListener("my-signature-pad-event", (event) => {
console.log("Received event:", (event as CustomEvent).detail);
});
<div
id="my-signature-pad"
class="signature-pad signature-pad-js"
data-on-draw-end="my-signature-pad-event"
>
<div data-part="root">
<label data-part="label">Signature Pad</label>
<input data-part="hidden-input" />
<div data-part="control">
<svg data-part="segment"></svg>
<button data-part="clear-trigger">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"
/>
</svg>
</button>
<div data-part="guide"></div>
</div>
<div data-part="preview"></div>
</div>
</div>
Open your browser's console to see the events received when the siganture pad draw ends
data-on-draw
Type: string
Description: Event name triggered while drawing on the signature pad.
data-on-draw-end
Type: string
Description: Event name triggered when drawing ends.
# Form usage
Signature pad can be used inside a form
You must set the id of the form and the name of the Signature pad
data-name="signature"
<form
id="my-form"
class="flex max-w-(--container-mini) flex-col items-center gap-(--spacing-ui-gap)"
>
<div class="signature-pad signature-pad-js" data-name="signature">
<div data-part="root">
<label data-part="label">Signature Pad</label>
<input data-part="hidden-input" />
<div data-part="control">
<svg data-part="segment"></svg>
<button data-part="clear-trigger">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99"
/>
</svg>
</button>
<div data-part="guide"></div>
</div>
</div>
</div>
<button class="button button--accent" type="submit">Submit</button>
<div id="result"></div>
</form>
You can use the results from the form as you wish
const signaturePadForm = document.getElementById(
"my-form",
) as HTMLFormElement | null;
const signatureResult = document.getElementById(
"result",
) as HTMLDivElement | null;
if (signaturePadForm && signatureResult) {
signaturePadForm.addEventListener("submit", (e: Event) => {
e.preventDefault();
const formData = new FormData(signaturePadForm);
console.log(formData.getAll("signature"));
const signature = (formData.get("signature") as string) || "none";
signatureResult.innerHTML = `Submitted: signature: <span class="overflow-scroll scrollbar scrollbar--sm max-h-(--container-mini) block max-w-(--container-mini) break-all">${signature}</span>`;
});
}
# Installation
First, complete the Corex UI initial installation guide for your platform, bundler, or framework.
- Import the component
import "@corex-ui/static/components/signature-pad";
This will automatically initialize all elements with class="signature-pad-js" and add the necessary interaction behavior.
- Add styling
The component is unstyled by default for maximum customization flexibility.
To apply the default Corex UI design system styles, import the stylesheet:
@import "@corex-ui/design/components/signature-pad.css";
These styles will be applied to all elements with the signature-pad class.