clickwrap
Version:
Complete clickwrap solution with built-in document viewing. Track agreements, signatures, and consents.
294 lines (233 loc) • 7.84 kB
Markdown
# SuperDoc Clickwrap
Orchestrate legal agreements with SuperDoc. Track document reading, signatures, and consent checkboxes without the UI overhead.
## Why this exists
SuperDoc is great at rendering documents. But legal agreements need more - scroll tracking, signatures, consent checkboxes. This orchestrator handles that coordination while you keep full control of your UI.
**Note:** Clickwrap includes SuperDoc internally. You don't need to install or initialize SuperDoc separately.
## Install
```bash
npm install clickwrap
```
## Quick Start
```javascript
import Clickwrap from 'clickwrap'
import SignaturePad from 'signature_pad'
// Initialize Clickwrap with built-in SuperDoc
const clickwrap = new Clickwrap({
// Document configuration - Clickwrap handles SuperDoc internally!
document: '/terms.pdf', // PDF/DOCX file or URL
documentElement: '#document', // Where to render
documentId: 'terms-v2.1', // Optional document identifier
// UI Components
signaturePad: new SignaturePad(canvas),
consentElements: document.querySelectorAll('.consent'),
acceptButton: document.querySelector('#accept'),
// Requirements
requirements: {
scrollThreshold: 0.95,
signature: true,
consents: ['terms', 'privacy']
},
// Callbacks
onReady: () => console.log('Document loaded!'),
onAccept: async (data) => {
// Send to your backend
await api.saveAgreement(data)
}
})
```
## What it does
✅ Handles SuperDoc initialization internally
✅ Tracks document scroll progress
✅ Validates signatures (bring your own signature library)
✅ Manages consent checkboxes
✅ Enables accept button when requirements are met
✅ Collects timestamped agreement data
✅ Provides progress tracking and validation states
## What it doesn't do
❌ No UI components - you build the interface
❌ No backend - you handle data storage
❌ No styling - you control the look
## The Data You Get
When a user accepts, you receive everything needed for legal compliance:
```javascript
{
timestamp: "2024-01-15T10:30:00Z",
documentId: "terms-v2.1",
documentUrl: "/terms.pdf", // if document was a URL
duration: 47, // seconds spent
scrollProgress: "100%", // how far they scrolled
signature: "data:image/png;...", // signature image (if required)
consents: {
terms: true,
privacy: true,
marketing: false
},
action: "accepted" // or "declined"
}
```
## API
### Config Options
```javascript
new Clickwrap({
// Document configuration
document: '/terms.pdf', // URL or File object (PDF/DOCX)
documentElement: '#document', // Selector or element where to render
documentId: 'terms-v2.1', // Optional document identifier
superdocConfig: {}, // Optional SuperDoc configuration
// Components (bring your own)
signaturePad: pad, // SignaturePad or compatible
consentElements: checkboxes, // Your checkbox elements
acceptButton: button, // Gets enabled when valid
declineButton: button, // Optional decline
// Requirements
requirements: {
scrollThreshold: 0.95, // 0-1 (95% = nearly complete)
signature: true, // Signature required?
consents: ['terms', 'privacy'] // Required checkbox names
},
// Callbacks
onReady: () => {}, // Document loaded and ready
onProgress: (state) => {}, // Track completion
onAccept: async (data) => {}, // Handle acceptance
onDecline: async (data) => {} // Handle rejection
})
```
### Methods
- `validate()` - Check if all requirements are met
- `getData()` - Get current agreement data
- `reset()` - Clear all inputs and start over
- `getProgress()` - Get completion percentage (returns {completed, total, percentage})
- `destroy()` - Clean up instance and SuperDoc
## React Example
```jsx
function AgreementModal({ document }) {
const canvasRef = useRef()
const clickwrapRef = useRef()
useEffect(() => {
// Initialize Clickwrap with built-in SuperDoc
const signaturePad = new SignaturePad(canvasRef.current)
clickwrapRef.current = new Clickwrap({
// Document configuration
document: document.url, // PDF/DOCX URL
documentElement: '#agreement-doc', // Where to render
documentId: document.id,
// UI Components
signaturePad,
consentElements: document.querySelectorAll('.consent'),
acceptButton: document.querySelector('#accept'),
// Requirements
requirements: {
scrollThreshold: 0.95,
signature: true,
consents: ['terms']
},
// Callbacks
onReady: () => {
console.log('Document loaded!')
},
onAccept: async (data) => {
await api.recordAgreement(data)
closeModal()
}
})
return () => {
clickwrapRef.current?.destroy()
}
}, [document])
return (
<div className="agreement-modal">
<div id="agreement-doc" />
<canvas ref={canvasRef} />
<label>
<input type="checkbox" name="terms" className="consent" />
I accept the terms
</label>
<button id="accept">Accept</button>
</div>
)
}
```
## Vue Example
```vue
<template>
<div class="agreement">
<div id="documentViewer"></div>
<canvas ref="signatureCanvas"></canvas>
<label>
<input type="checkbox" name="terms" ref="termsCheck">
Accept terms
</label>
<button ref="acceptBtn">Accept</button>
</div>
</template>
<script setup>
import { onMounted, onUnmounted, ref } from 'vue'
import Clickwrap from 'clickwrap'
import SignaturePad from 'signature_pad'
const props = defineProps(['documentUrl'])
const emit = defineEmits(['accepted'])
const signatureCanvas = ref()
const termsCheck = ref()
const acceptBtn = ref()
let clickwrap = null
onMounted(() => {
clickwrap = new Clickwrap({
// Document configuration
document: props.documentUrl,
documentElement: '#documentViewer',
// UI Components
signaturePad: new SignaturePad(signatureCanvas.value),
consentElements: [termsCheck.value],
acceptButton: acceptBtn.value,
// Requirements
requirements: {
signature: true,
consents: ['terms']
},
// Callbacks
onReady: () => {
console.log('Document ready!')
},
onAccept: async (data) => {
await saveAgreement(data)
emit('accepted')
}
})
})
onUnmounted(() => {
clickwrap?.destroy()
})
</script>
```
## Without SuperDoc
Works with any scrollable element if you don't need document rendering:
```javascript
const clickwrap = new Clickwrap({
// No 'document' parameter - just track existing element
documentElement: document.querySelector('.terms-text'),
documentId: 'terms-v2.1',
signaturePad: new SignaturePad(canvas),
consentElements: document.querySelectorAll('.consent'),
acceptButton: document.querySelector('#accept'),
requirements: {
scrollThreshold: 0.95,
signature: true,
consents: ['terms']
},
onAccept: async (data) => {
await api.saveAgreement(data)
}
})
```
## Signature Libraries
Works with any signature library that has `isEmpty()` and `clear()` methods:
- [signature_pad](https://github.com/szimek/signature_pad) ✅
- [React Signature Canvas](https://github.com/agilgur5/react-signature-canvas) ✅
- [Vue Signature Pad](https://github.com/neighborhood999/vue-signature-pad) ✅
- Custom implementations ✅
## Browser Support
Modern browsers only. No IE11.
## License
MIT
## About
Built by the SuperDoc team to make legal agreements easier. Part of the [SuperDoc](https://github.com/Harbour-Enterprises/SuperDoc) ecosystem.