Signature
The signature component allows users to draw handwritten signatures using touch or pointer devices. The signature can be saved as an image or cleared.
Draw your signature in the area below
0 strokes
Draw your signature in the area below
0 strokes
Features
Install
Install the component from your command line.
Anatomy
Import all parts and piece them together.
<script setup lang="ts"> import * as signature from "@destyler/signature" import { useMachine, normalizeProps } from "@destyler/vue" import { computed, useId } from "vue"
const [state, send] = useMachine(signature.machine({ id: useId() }))
const api = computed(() => signature.connect(state.value, send, normalizeProps), )</script>
<template> <div v-bind="api.getRootProps()"> <label v-bind="api.getLabelProps()"></label>
<div v-bind="api.getControlProps()"> <svg v-bind="api.getSegmentProps()"> <path v-for="(path, i) of api.paths" :key="i" v-bind="api.getSegmentPathProps({ path })" /> <path v-if="api.currentPath" v-bind="api.getSegmentPathProps({ path: api.currentPath })" /> </svg> <button v-bind="api.getClearTriggerProps()"></button> <div v-bind="api.getGuideProps()"></div> </div> <button v-bind="api.getClearTriggerProps()"/> </div></template>import { normalizeProps, useMachine } from '@destyler/react'import * as signature from '@destyler/signature'import { useId, useMemo } from 'react'
export default function Signature() {
const [state, send] = useMachine(signature.machine({ id: useId() }))
const api = useMemo( () => signature.connect(state, send, normalizeProps), [state, send], )
return ( <div {...api.getRootProps()}> <label {...api.getLabelProps()}></label>
<div {...api.getControlProps()}> <svg {...api.getSegmentProps()} > {api.paths.map((path, i) => ( <path key={i} {...api.getSegmentPathProps({ path })}/> ))} {api.currentPath && ( <path {...api.getSegmentPathProps({ path: api.currentPath })}/> )} </svg> <button {...api.getClearTriggerProps()}></button> <div {...api.getGuideProps()}></div> </div> <button {...api.getClearTriggerProps()}></button> </div> )}<script lang="ts"> import * as signature from "@destyler/signature" import { useMachine, normalizeProps } from "@destyler/svelte"
const id = $props.id() const [state, send] = useMachine(signature.machine({ id }))
const api = $derived(signature.connect(state, send, normalizeProps))</script>
<div {...api.getRootProps()}> <label {...api.getLabelProps()}></label> <div {...api.getControlProps()}> <svg {...api.getSegmentProps()} > {#each api.paths as path, i} <path {...api.getSegmentPathProps({ path })}/> {/each} {#if api.currentPath} <path {...api.getSegmentPathProps({ path: api.currentPath })}/> {/if} </svg> <button {...api.getClearTriggerProps()}></button> <div {...api.getGuideProps()}></div> </div> <button {...api.getClearTriggerProps()}></button></div>import * as signature from '@destyler/signature'import { normalizeProps, useMachine } from '@destyler/solid'import { createMemo, createUniqueId, For } from 'solid-js'
export default function Signature() { const id = createUniqueId()
const [state, send] = useMachine(signature.machine({ id }))
const api = createMemo(() => signature.connect(state, send, normalizeProps), )
return ( <div {...api().getRootProps()}> <label {...api().getLabelProps()} ></label>
<div {...api().getControlProps()} > <svg {...api().getSegmentProps()} > <For each={api().paths}> {(path, i) => ( <path {...api().getSegmentPathProps({ path })}/> )} </For> {api().currentPath && ( <path {...api().getSegmentPathProps({ path: api().currentPath! })}/> )} </svg> <button {...api().getClearTriggerProps()}></button> <div {...api().getGuideProps()}> </div> </div> <button {...api().getClearTriggerProps()}></button> </div> )}Listening to drawing events
The signature component emits the following events:
-
onDraw: Emitted when the user is drawing the signature. -
onDrawEnd: Emitted when the user stops drawing the signature.
const [state, send] = useMachine( signature.machine({ onDraw(details) { // details => { path: string[] } console.log("Drawing signature", details) }, onDrawEnd(details) { // details => { path: string[], toDataURL: () => string } console.log("Signature drawn", details) }, }),)Clearing the signature
To clear the signature, use the api.clear(),
or render the clear trigger button.
<script setup lang="ts"> import * as signature from "@destyler/signature" import { useMachine, normalizeProps } from "@destyler/vue" import { computed, useId } from "vue"
const [state, send] = useMachine(signature.machine({ id: useId() }))
const api = computed(() => signature.connect(state.value, send, normalizeProps), )</script>
<template> <button @click="api.clear()">clear</button></template>import { normalizeProps, useMachine } from '@destyler/react'import * as signature from '@destyler/signature'import { useId, useMemo } from 'react'
export default function Signature() {
const [state, send] = useMachine(signature.machine({ id: useId() }))
const api = useMemo( () => signature.connect(state, send, normalizeProps), [state, send], )
return ( <button onClick={() => api.clear()}> clear </button> )}<script lang="ts"> import * as signature from "@destyler/signature" import { useMachine, normalizeProps } from "@destyler/svelte"
const id = $props.id() const [state, send] = useMachine(signature.machine({ id }))
const api = $derived(signature.connect(state, send, normalizeProps))</script>
<button on:click={() => api.clear()}> clear</button>import * as signature from '@destyler/signature'import { normalizeProps, useMachine } from '@destyler/solid'import { createMemo, createUniqueId, For } from 'solid-js'
export default function Signature() { const id = createUniqueId()
const [state, send] = useMachine(signature.machine({ id }))
const api = createMemo(() => signature.connect(state, send, normalizeProps), )
return ( <button onClick={() => api().clear()}> clear </button> )}Rendering an image preview
Use the api.getDataUrl() method to get the signature as a data URL and render it as an image.
You can also leverage the onDrawEnd event to get the signature data URL.
<script setup lang="ts"> import * as signature from "@destyler/signature" import { useMachine, normalizeProps } from "@destyler/vue" import { computed, useId, ref } from "vue"
const imageURL = ref<string | null>(null)
const [state, send] = useMachine(signature.machine({ id: useId(), onDrawEnd(details) { details.getDataUrl("image/png").then((url) => { // set the image URL in local state imageURL.value = url }) }, }))
const api = computed(() => signature.connect(state.value, send, normalizeProps), )</script>
<template> <img :src="imageURL" alt="Signature" /></template>import * as signature from '@destyler/signature'import { normalizeProps, useMachine } from '@destyler/react'import { useId, useMemo, useState } from 'react'
export default function Signature() { const [imageURL, setImageURL] = useState<string | null>(null)
const [state, send] = useMachine(signature.machine({ id: useId(), onDrawEnd(details) { details.getDataUrl("image/png").then((url) => { // set the image URL in local state setImageURL(url) }) }, }))
const api = useMemo( () => signature.connect(state, send, normalizeProps), [state, send], )
return ( <img src={imageURL} alt="Signature" /> )}<script lang="ts"> import * as signature from "@destyler/signature" import { useMachine, normalizeProps } from "@destyler/svelte"
let imageURL: string | null = null
const id = $props.id() const [state, send] = useMachine(signature.machine({ id, onDrawEnd(details) { details.getDataUrl("image/png").then((url) => { // set the image URL in local state imageURL = url }) }, }))
const api = $derived(signature.connect(state, send, normalizeProps))</script>
<img src={imageURL} alt="Signature" />import * as signature from '@destyler/signature'import { normalizeProps, useMachine } from '@destyler/solid'import { createMemo, createUniqueId, createSignal } from 'solid-js'
export default function Signature() { const id = createUniqueId() const [imageURL, setImageURL] = createSignal<string | null>(null)
const [state, send] = useMachine(signature.machine({ id, onDrawEnd(details) { details.getDataUrl("image/png").then((url) => { // set the image URL in local state imageURL = url }) }, }))
const api = createMemo(() => signature.connect(state, send, normalizeProps), )
return ( <img src={imageURL} alt="Signature" /> )}Changing the stroke color
To change the stroke color,
set the drawing.fill option to a valid CSS color.
You can’t use a css variable as the stroke color.
const [state, send] = useMachine( signature.machine({ drawing: { fill: "blue", }, }),)Changing the stroke width
To change the stroke width, set the drawing.size option to a number.
const [state, send] = useMachine( signature.machine({ drawing: { size: 5, }, }),)Simulating pressure sensitivity
Pressure sensitivity is disabled by default.
To enable it, set the drawing.simulatePressure option to true.
const [state, send] = useMachine( signature.machine({ drawing: { simulatePressure: true, }, }),)Using in form
To use the signature pad in a form, set the name context property.
<script setup lang="ts"> import * as signature from "@destyler/signature" import { useMachine, normalizeProps } from "@destyler/vue" import { computed, useId, ref } from "vue"
const imageURL = ref<string | null>(null)
const [state, send] = useMachine(signature.machine({ id: useId(), name: "signature", onDrawEnd(details) { details.getDataUrl("image/png").then((url) => { // set the image URL in local state imageURL.value = url }) }, }))
const api = computed(() => signature.connect(state.value, send, normalizeProps), )</script>
<template> <input v-bind="api.getHiddenInputProps({ value: imageURL })" /></template>import * as signature from '@destyler/signature'import { normalizeProps, useMachine } from '@destyler/react'import { useId, useMemo, useState } from 'react'
export default function Signature() { const [imageURL, setImageURL] = useState<string | null>(null)
const [state, send] = useMachine(signature.machine({ id: useId(), name: "signature", onDrawEnd(details) { details.getDataUrl("image/png").then((url) => { // set the image URL in local state setImageURL(url) }) }, }))
const api = useMemo( () => signature.connect(state, send, normalizeProps), [state, send], )
return ( <input {...api.getHiddenInputProps({ value: imageURL })} /> )}<script lang="ts"> import * as signature from "@destyler/signature" import { useMachine, normalizeProps } from "@destyler/svelte"
let imageURL: string | null = null
const id = $props.id() const [state, send] = useMachine(signature.machine({ id, name: "signature", onDrawEnd(details) { details.getDataUrl("image/png").then((url) => { // set the image URL in local state imageURL = url }) }, }))
const api = $derived(signature.connect(state, send, normalizeProps))</script>
<input {...api.getHiddenInputProps({ value: imageURL })} />import * as signature from '@destyler/signature'import { normalizeProps, useMachine } from '@destyler/solid'import { createMemo, createUniqueId, createSignal } from 'solid-js'
export default function Signature() { const id = createUniqueId() const [imageURL, setImageURL] = createSignal<string | null>(null)
const [state, send] = useMachine(signature.machine({ id, onDrawEnd(details) { details.getDataUrl("image/png").then((url) => { // set the image URL in local state imageURL = url }) }, }))
const api = createMemo(() => signature.connect(state, send, normalizeProps), )
return ( <input {...api().getHiddenInputProps({ value: imageURL })} /> )}Disabling the signature
Set the disabled context property to true to disable the signature.
const [state, send] = useMachine( signature.machine({ disabled: true, }),)Make the signature read only
Set the readOnly context property to true to make the signature pad read only.
const [state, send] = useMachine( signature.machine({ readOnly: true, }),)Methods and Properties
Machine Context
The signature machine exposes the following context properties:
Partial<{ root: string; control: string; hiddenInput: string; label: string; }>IntlTranslations(details: DrawDetails) => void(details: DrawEndDetails) => voidDrawingOptionsbooleanbooleanbooleanstring"ltr" | "rtl"string() => ShadowRoot | Node | DocumentMachine API
The signature api exposes the following methods:
booleanbooleanstringstring[](type: DataUrlType, quality?: number) => Promise<string>() => voidData Attributes
Root
data-scopedata-partdata-disabledLabel
data-scopedata-partdata-disabledControl
data-scopedata-partdata-disabledGuide
data-scopedata-partdata-disabled