SignPdf
Drag-and-drop PDF signing with fixed placement, non-overlapping markers, and PDF export. The layout combines upload controls, zoom, signer list, and a detail panel so users aged 20–45 can review and finish documents without switching pages.
Example
Drag user chips into the canvas area to pin a signature where it belongs. In this demo, the page only provides persistence callbacks. SignPdf takes care of the upload UI, drag/drop, and saving signature fields automatically.
How it works:
- Upload a PDF using the built-in upload control.
- Drag a signer into the PDF to create a signature field.
- The component saves fields as they are created or updated.
Code
vue
<script setup lang="ts">
import { SignPdf } from '@point-hub/papp'
const demoUsers = [
{ id: 'alya', name: 'Alya Rahma', initials: 'AR', label: 'Menyetujui' },
{ id: 'dimas', name: 'Dimas Pratama', initials: 'DP', label: 'Mengetahui' }
]
const currentUser = demoUsers[0]
const persistence = {
uploadPdf: async (file: File) => {
// Upload to your storage and return the PDF URL.
return { pdfUrl: 'https://.../your.pdf', fileUrl: 'storage/..', fileName: file.name }
},
createDocument: async ({ title, fileUrl, ownerId }) => {
// Save document metadata to your DB and return the document ID.
return 'docId'
},
saveSignatureField: async ({ docId, signature }) => {
// Persist each field (page, x, y, width, height, assignedTo, signed, signedAt).
}
}
</script>
<template>
<SignPdf :users="demoUsers" :current-user="currentUser" :persistence="persistence" />
</template>SignPdf API
Types
ts
export interface SignPdfUser {
id: number | string
name: string
initials?: string
role?: string
label?: string
}
export interface PdfSignerSignature {
id: string
x: number
y: number
width: number
height: number
page: number
userId: number | string | null
name: string
initials: string
label?: string
signed: boolean
}
export interface PdfSignerPersistence {
uploadPdf?: (file: File) => Promise<{ pdfUrl: string; fileUrl?: string; fileName?: string }>
createDocument?: (payload: { title: string; fileUrl?: string; ownerId: number | string | null }) => Promise<string>
saveSignatureField?: (payload: {
docId: string | null
signature: PdfSignerSignature
action: 'create' | 'update' | 'sign'
}) => Promise<void>
lockSignatures?: (docId: string | null, signatures: PdfSignerSignature[]) => Promise<void>
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
users | SignPdfUser[] | built-in demo list | Signers that can be dragged to the canvas. |
fontUrl | string | /fonts/DancingScript.ttf | Font used when exporting signed fields with Dancing Script initials. |
initialScale | number | 0.8 | Initial zoom for the rendered page. |
minScale | number | 0.6 | Minimum zoom level. |
maxScale | number | 2.4 | Maximum zoom level. |
currentUser | `SignPdfUser | null` | null |
pdfUrl | string | '' | PDF source URL to load immediately. |
documentId | `string | null` | null |
persistence | PdfSignerPersistence | undefined | Optional persistence hooks (upload, save fields, etc.). |
enableUpload | boolean | true | Show or hide the built-in upload control. |
Events
| Event | Payload | When |
|---|---|---|
signature:create | PdfSignerSignature | A signature field is added to the canvas. |
signature:update | PdfSignerSignature | A signature field finishes moving. |
signature:sign | PdfSignerSignature | A signature field is signed by the active user. |
Exposed methods
| Method | Returns | Description |
|---|---|---|
getSignatures() | PdfSignerSignature[] | Read all signature fields on the canvas. |
getDocumentId() | `string | null` |
lockPositions() | void | Lock signature positions to prevent dragging. |