Signature
Digital signature field with canvas drawing and typed mode
Overview
Form.Field.Signature provides a digital signature input for legal forms, contracts, and consent documents. Users can draw with mouse/finger or type their name in cursive font.
Full example
The complete sandbox example, read directly from the form-develop-app / form-develop-app-shadcn
source at build time. The shadcn side (FieldSignature) lives inside the broader "specialized
fields" demo, alongside Editable, ColorPicker, and FileUpload — not as a standalone page.
'use client'
import { Code, Heading, Image, Text, VStack } from '@chakra-ui/react'
import { Form } from '@letar/forms'
import { useState } from 'react'
import { z } from 'zod/v4'
import { DemoPageLayout } from '../_components'
const ContractSchema = z
.object({
name: z
.string()
.min(1, 'Required')
.meta({ ui: { title: 'Full Name' } }),
signature: z.string().min(1, 'Signature is required'),
})
.strip()
export default function SignatureDemoPage() {
const [result, setResult] = useState<Record<string, unknown> | null>(null)
return (
<DemoPageLayout title="Signature Field" description="Form.Field.Signature — canvas drawing + typed mode">
{/* Draw mode (по умолчанию) */}
<VStack gap={4} align="stretch">
<Heading size="lg">1. Draw + Typed Mode</Heading>
<Text color="fg.muted">Рисуйте мышью/пальцем или введите имя для курсивной подписи.</Text>
<Form initialValue={{ name: '', signature: '' }} schema={ContractSchema} onSubmit={(data) => setResult(data)}>
<Form.Field.String name="name" label="Full Name" />
<Form.Field.Signature name="signature" label="Your Signature" placeholder="Sign here" clearLabel="Clear" />
<Form.Button.Submit>Sign Contract</Form.Button.Submit>
</Form>
</VStack>
{/* Кастомные настройки */}
<VStack gap={4} align="stretch" mt={8}>
<Heading size="lg">2. Custom Style</Heading>
<Text color="fg.muted">Синяя подпись, увеличенный canvas, толстая линия.</Text>
<Form initialValue={{ signature: '' }} onSubmit={(data) => setResult(data)}>
<Form.Field.Signature
name="signature"
label="Premium Signature"
width={500}
height={200}
strokeColor="#1a365d"
strokeWidth={3}
backgroundColor="#f7fafc"
placeholder="Sign with style"
/>
<Form.Button.Submit>Submit</Form.Button.Submit>
</Form>
</VStack>
{/* Draw only (без typed mode) */}
<VStack gap={4} align="stretch" mt={8}>
<Heading size="lg">3. Draw Only (no typed)</Heading>
<Form initialValue={{ signature: '' }} onSubmit={(data) => setResult(data)}>
<Form.Field.Signature
name="signature"
label="Handwritten Only"
allowTyped={false}
placeholder="Draw your signature"
/>
<Form.Button.Submit>Submit</Form.Button.Submit>
</Form>
</VStack>
{/* Результат */}
{result && (
<VStack gap={2} align="stretch" mt={8}>
<Heading size="md">Submitted Data</Heading>
{typeof result.signature === 'string' && result.signature.startsWith('data:') && (
<Image
src={result.signature as string}
alt="Signature"
border="1px solid"
borderColor="border"
borderRadius="md"
maxW="400px"
/>
)}
<Code whiteSpace="pre" maxH="200px" overflow="auto">
{JSON.stringify(
{ ...result, signature: result.signature ? `${(result.signature as string).slice(0, 50)}...` : '' },
null,
2,
)}
</Code>
</VStack>
)}
</DemoPageLayout>
)
}'use client'
import { FieldColorPicker, FieldEditable, FieldFileUpload, FieldSignature } from '@letar/forms-shadcn'
import { useState } from 'react'
import { DemoForm, DemoPageLayout, SubmittedDataPreview } from '../_components'
interface SpecializedValues {
bio2: string
brandColor: string
attachments: File[]
signature: string
}
const defaultValues: SpecializedValues = {
bio2: 'Кликните для редактирования',
brandColor: '#4299E1',
attachments: [],
signature: '',
}
export default function SpecializedDemoPage() {
const [submitted, setSubmitted] = useState<SpecializedValues | null>(null)
return (
<DemoPageLayout
title="Специализированные поля"
description="Editable, ColorPicker, FileUpload (dropzone), Signature"
>
<DemoForm<SpecializedValues> defaultValues={defaultValues} onSubmit={setSubmitted}>
<FieldEditable name="bio2" label="Кликабельный текст" />
<FieldColorPicker name="brandColor" label="Цвет бренда" />
<FieldFileUpload
name="attachments"
label="Вложения"
variant="dropzone"
maxFiles={3}
showSize
dropzoneDescription="До 3 файлов"
/>
<FieldSignature name="signature" label="Подпись" width={320} height={120} />
<button
type="submit"
className="bg-primary text-primary-foreground rounded-md px-4 py-2 text-sm font-medium"
>
Отправить
</button>
</DemoForm>
<SubmittedDataPreview data={submitted} />
</DemoPageLayout>
)
}Vue-пример для этого поля появится позже.
Angular-пример для этого поля появится позже.
Basic Usage
<Form initialValue={{ signature: '' }} onSubmit={handleSubmit}>
<Form.Field.Signature name="signature" label="Your Signature" />
<Form.Button.Submit>Sign</Form.Button.Submit>
</Form>The field value is a data URI string (image/png base64), suitable for storage in a database or submission to an API.
Draw Mode
The default mode. Users draw directly on the canvas with mouse or touch.
<Form.Field.Signature
name="signature"
label="Signature"
width={400}
height={150}
strokeColor="black"
strokeWidth={2}
placeholder="Sign here"
clearLabel="Clear"
/>Typed Mode
Alternative to drawing — users type their name and it renders in a cursive font on the canvas.
<Form.Field.Signature name="signature" allowTyped={true} typedFont="'Dancing Script', cursive" />Toggle between Draw and Type modes via the segmented control at the top.
Draw Only
Disable typed mode for cases where handwritten signatures are required:
<Form.Field.Signature name="signature" allowTyped={false} />Custom Styling
<Form.Field.Signature
name="signature"
width={500}
height={200}
strokeColor="#1a365d"
strokeWidth={3}
backgroundColor="#f7fafc"
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
width | number | 400 | Canvas width in pixels |
height | number | 150 | Canvas height in pixels |
strokeColor | string | 'black' | Pen/stroke color |
strokeWidth | number | 2 | Pen/stroke width |
backgroundColor | string | 'white' | Canvas background |
clearLabel | string | 'Clear' | Clear button text |
placeholder | string | 'Sign here' | Placeholder over empty canvas |
allowTyped | boolean | true | Show typed signature mode |
typedFont | string | cursive | Font for typed mode |
Accessibility
- Canvas has
role="img"andaria-label="Signature pad" - Tab focus shows visible outline
- Typed mode serves as keyboard-accessible alternative
- Clear button is keyboard-accessible
Touch Support
Full touch support for mobile devices:
touchAction: noneprevents scrolling while drawing- Touch events (touchstart, touchmove, touchend) handled alongside mouse events
Validation
Use Zod z.string().min(1) to require a signature:
const Schema = z.object({
signature: z.string().min(1, 'Signature is required'),
})The field value is empty string '' when canvas is blank, and a data URI when drawn/typed.
Live Example
Try the interactive example on forms-example.letar.best.