Integrare il Signer di Legalesign nel tuo sito web
Il componente Signer richiede l'attivazione. Contatta il supporto per abilitarlo per il tuo team.
Versione corrente: v1.1.7 — changelog
Il Legalesign Signer è un componente web indipendente dalla piattaforma che offre un'esperienza completa e senza interruzioni per la firma dei documenti all'interno della tua app. Funziona con HTML vanilla, React, Vue, Angular o qualsiasi framework web.
Incorpora questo componente ovunque i tuoi utenti debbano firmare documenti — all'interno di un CRM, di un portale clienti o di qualsiasi applicazione interna che renderizza HTML.
Installazione
Carica direttamente dal CDN (nessuna installazione richiesta):
<script type="module" src="https://cdn.legalesign.io/signer/latest/ls-signer.esm.js"></script>
Installazione React
Installa tramite un package manager:
npm install legalesign-signer
# or
pnpm add legalesign-signer
Integrazione base
HTML e JavaScript
<ls-signer
recipient-id="abc123"
private-key="key"
session-id="session"
></ls-signer>
<script>
const signer = document.querySelector('ls-signer');
signer.addEventListener('signingSuccess', (e) => console.log('Signed:', e.detail.eventType, e.detail.documentId));
signer.addEventListener('signingFail', (e) => console.error('Failed:', e.detail.failureReason, e.detail.error));
signer.addEventListener('fieldChange', (e) => console.log('Field event:', e.detail.eventType));
</script>
React
import { useEffect, useState } from 'react';
import { LsSigner } from 'legalesign-signer/react';
import 'legalesign-signer/react.css';
function SigningPage() {
const [signerData, setSignerData] = useState(null);
useEffect(() => {
fetch('/your-backend/to-get-token')
.then(res => res.json())
.then(setSignerData);
}, []);
if (!signerData) return <p>Loading...</p>;
return (
<LsSigner
recipientId={signerData.recipientId}
privateKey={signerData.token}
sessionId={signerData.sessionId}
onSuccess={({ eventType, documentId }) => console.log(eventType, documentId)}
onFail={({ eventType, failureReason, error }) => console.error(eventType, failureReason, error)}
onChange={({ eventType, uuid, saved, field, document }) => console.log('Event:', eventType)}
/>
);
}
React richiede react e react-dom (v18 o v19) come dipendenze peer.
Vue
<template>
<ls-signer
ref="signer"
:recipient-id="recipientId"
:private-key="privateKey"
:session-id="sessionId"
/>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
const signer = ref(null);
function handleSuccess(e) {
console.log('Signed:', e.detail);
}
function handleFail(e) {
console.error('Failed:', e.detail);
}
onMounted(() => {
signer.value.addEventListener('signingSuccess', handleSuccess);
signer.value.addEventListener('signingFail', handleFail);
});
onBeforeUnmount(() => {
signer.value?.removeEventListener('signingSuccess', handleSuccess);
signer.value?.removeEventListener('signingFail', handleFail);
});
</script>
Se usi Vue con Vite, aggiungi isCustomElement: (tag) => tag.startsWith('ls-') nella configurazione del plugin Vue per sopprimere gli avvisi di elementi sconosciuti.
Vue 3 trasforma in minuscolo i nomi degli eventi sugli elementi custom, quindi @signingSuccess non funzionerà. Usa addEventListener sul riferimento all'elemento come mostrato sopra.
Racchiudi <ls-signer> in <ClientOnly> per evitare errori SSR. Aggiungi la configurazione per l'elemento custom in nuxt.config.ts:
export default defineNuxtConfig({
vue: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('ls-'),
},
},
});
Autenticazione
Il componente signer richiede un token a breve termine dal tuo backend. Ci sono due opzioni:
- GraphQL
generateComponentToken— Chiamare concomponent: LS_SIGNERe uno trarecipientIdosessionIdnell'ambito del signer (fornire uno, non entrambi). - REST API — Chiamare
GET /signer/{signerId}/component-token/con la tua API key.
Entrambi restituiscono il token e il sessionId necessari al componente. Consulta Widget Authorization per il flusso completo del token lato server.
Opzione 1: GraphQL (Node.js)
Usando recipientId (il più comune — usalo quando conosci il destinatario ma non hai ancora una sessione):
const response = await fetch('https://graphql.uk.legalesign.com/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.LEGALESIGN_API_KEY}`,
},
body: JSON.stringify({
query: `mutation MintSignerToken($input: GenerateComponentTokenInput!) {
generateComponentToken(input: $input) {
token
tokenType
sessionId
expiresIn
expiresAt
}
}`,
variables: {
input: {
component: 'LS_SIGNER',
signer: { recipientId: '<recipient-id>' }
}
}
})
});
const { data } = await response.json();
const { token, sessionId } = data.generateComponentToken;
In alternativa, se hai già un sessionId da una chiamata precedente:
variables: {
input: {
component: 'LS_SIGNER',
signer: { sessionId: '<session-id>' }
}
}
Opzione 2: REST API
const response = await fetch(
`https://eu-api.legalesign.com/api/v1/signer/${signerId}/component-token/`,
{
headers: {
Authorization: `Bearer ${process.env.LEGALESIGN_API_KEY}`,
},
}
);
const { token, sessionId } = await response.json();
Passa token come private-key e sessionId come session-id al componente.
Attributi obbligatori
| Attributo | Tipo | Descrizione |
|---|---|---|
recipient-id | string | Identificatore del destinatario (base64, prefisso rec, o UUID) |
private-key | string | Token restituito da generateComponentToken |
session-id | string | ID sessione restituito da generateComponentToken |
Attributi opzionali
| Attributo | Tipo | Predefinito | Descrizione |
|---|---|---|---|
colour | string | blue | Nome del tema colore (vedi Theming) |
style | string | `` | Modifiche di stile (vedi Customer CSS) |
branding | boolean | true | Mostra il branding Legalesign. Impostare su false per rimuoverlo. |
language | string | — | Forza una lingua specifica e nasconde il selettore di lingua (vedi Internazionalizzazione) |
Eventi
| Prop React | Evento componente web | eventType | Quando |
|---|---|---|---|
onSuccess | signingSuccess | "success" | Documento firmato con successo |
onFail | signingFail | "failure" | Firma del documento fallita, rifiutata, scaduta, cancellata, eliminata, rimossa o già completata altrove |
onChange | fieldChange | "ready" | Documento e immagini completamente caricate |
onChange | fieldChange | "save" | Un valore del campo è stato salvato |
onChange | fieldChange | "select" | Un campo è stato selezionato o ha ricevuto il focus |
onSuccess / signingSuccess
Attivato quando il destinatario firma correttamente il documento.
{
eventType: 'success';
documentId: string; // UUID of the signed document
recipientId: string; // UUID of the recipient
}
React:
<LsSigner
onSuccess={({ eventType, documentId, recipientId }) => {
console.log(eventType); // "success"
console.log(documentId);
console.log(recipientId);
}}
/>
Componente web:
signer.addEventListener('signingSuccess', (e) => {
console.log(e.detail.eventType); // "success"
console.log(e.detail.documentId);
console.log(e.detail.recipientId);
});
onFail / signingFail
Attivato quando la firma fallisce — sia per rifiuto del documento sia per errore durante il processo di firma (es. errore di rete, sessione scaduta, conflitto di stato del documento).
{
eventType: 'failure';
failureReason: FailureReason;
error: string; // Human-readable error message
documentId?: string; // UUID of the document (if available)
recipientId: string; // UUID of the recipient
}
failureReason | Causa |
|---|---|
documentExpired | Stato del documento state è "expired" oppure la data expires è passata |
sessionExpired | API ha restituito 401 o 403 durante il caricamento del documento |
cancelled | Stato del documento state è "cancelled" |
deleted | Flag is_deleted del documento è true |
rejected | Il destinatario ha rifiutato il documento (is_rejected è true) |
removed | API ha restituito 404 — il documento non esiste più |
documentCompleted | L'API di firma ha restituito completed — il documento era già firmato, probabilmente su un altro browser o dispositivo. Il componente mostra un messaggio informativo al destinatario invece di un errore. |
signingError | Qualsiasi altro errore durante il caricamento o la firma |
React:
<LsSigner
onFail={({ eventType, failureReason, error, documentId, recipientId }) => {
console.log(eventType); // "failure"
console.log(failureReason); // e.g. "documentExpired"
console.log(error);
}}
/>
Componente web:
signer.addEventListener('signingFail', (e) => {
console.log(e.detail.eventType); // "failure"
console.log(e.detail.failureReason); // e.g. "documentExpired"
console.log(e.detail.error);
});
onChange / fieldChange
I tre valori di eventType condividono lo stesso evento. Usa eventType per distinguere.
eventType: "ready"
Attivato una volta quando il documento e tutte le immagini delle pagine sono completamente caricate e l'interfaccia di firma è pronta per l'interazione.
{
eventType: 'ready';
document: {
documentId: string; // UUID of the document
name: string; // Document name
state: string; // Document state (e.g. "signing")
recipientId: string; // UUID of the recipient
recipientRole?: string; // Role of the recipient (e.g. "witness")
pageCount: number; // Number of pages
expires?: string; // Expiry date (ISO string, if set)
isApprover: boolean; // Whether the recipient is an approver
isWitness: boolean; // Whether the recipient is a witness
canReassign: boolean; // Whether the recipient can reassign
doOfferReject: boolean; // Whether the reject option is shown
};
}
React:
<LsSigner
onChange={({ eventType, document }) => {
if (eventType === 'ready') {
console.log('Ready to sign:', document.documentId, document.name);
console.log('Pages:', document.pageCount);
console.log('Expires:', document.expires);
}
}}
/>
Componente web:
signer.addEventListener('fieldChange', (e) => {
if (e.detail.eventType === 'ready') {
console.log('Ready to sign:', e.detail.document.documentId, e.detail.document.name);
}
});
eventType: "save"
Attivato dopo che un valore di campo è stato salvato sul server.
{
eventType: 'save';
uuid: string; // UUID of the field
saved: boolean; // Whether the save was successful
field: Record<string, any>; // Full field object (see Field Properties below)
}
React:
<LsSigner
onChange={({ eventType, uuid, saved, field }) => {
if (eventType === 'save') {
console.log(uuid, saved, field.value);
}
}}
/>
Componente web:
signer.addEventListener('fieldChange', (e) => {
if (e.detail.eventType === 'save') {
console.log(e.detail.uuid, e.detail.saved, e.detail.field.value);
}
});
eventType: "select"
Attivato quando un campo viene selezionato o riceve il focus — scatenato da click utente, navigazione da tastiera, auto-inoltro o interazione con la sidebar.
{
eventType: 'select';
uuid: string; // UUID of the selected field
field: Record<string, any>; // Full field object (see Field Properties below)
}
React:
<LsSigner
onChange={({ eventType, uuid, field }) => {
if (eventType === 'select') {
console.log('selected', uuid, field.fieldtype);
}
}}
/>
Componente web:
signer.addEventListener('fieldChange', (e) => {
if (e.detail.eventType === 'select') {
console.log('selected', e.detail.uuid, e.detail.field.fieldtype);
}
});
Proprietà del campo
L'oggetto field incluso negli eventi save e select contiene le seguenti proprietà:
| Proprietà | Tipo | Descrizione |
|---|---|---|
uuid | string | Identificatore unico del campo |
fieldtype | string | Tipo di campo (es. "text", "signature", "date", "checkbox") |
value | string | Valore corrente del campo |
state | boolean | Se il campo è stato salvato con successo |
optional | boolean | Se il campo è opzionale |
page | number | Numero della pagina su cui il campo appare |
label | string | Etichetta del campo (se impostata) |
validation | number | Codice tipo di validazione |
logicaction | string | Tipo azione logica ("1" = radio, "2" = somma, "3" = condizionale) |
logicgroup | string | Identificatore del gruppo logico |
mapto | string | Gruppo target per la logica (campi controller) |
auto | boolean | Se il campo è auto-popolato |
dirty | boolean | Se il campo ha modifiche locali non salvate |
Props React
Il componente React usa props camelCase e callback invece di eventi DOM:
| Prop | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
recipientId | string | ✅ | Identificatore del destinatario |
privateKey | string | ✅ | Chiave privata dalla mutation generateComponentToken |
sessionId | string | ✅ | Identificatore della sessione |
colour | LsSignerColour | ❌ | Colore del tema |
branding | boolean | ❌ | Mostra branding Legalesign. Default true. |
language | string | ❌ | Forza una lingua specifica (vedi Internazionalizzazione) |
onSuccess | (data: { eventType: 'success'; documentId: string; recipientId: string }) => void | ❌ | Chiamato al successo della firma |
onFail | (data: { eventType: 'failure'; failureReason: FailureReason; error: string; documentId?: string; recipientId: string }) => void | ❌ | Chiamato al fallimento della firma |
onChange | (data: { eventType: 'ready' | 'save' | 'select'; document?: DocumentSummary; uuid?: string; saved?: boolean; field?: Record<string, any> }) => void | ❌ | Chiamato per eventi di campo e al caricamento del documento |
Gestore generico (debug & prototipazione)
Poiché ogni evento include eventType, puoi collegare una singola funzione a tutti gli eventi:
React:
const handleSignerEvent = (e) => {
switch (e.eventType) {
case 'success': console.log('Signed:', e.documentId); break;
case 'failure': console.log('Failed:', e.failureReason, e.error); break;
case 'ready': console.log('Ready:', e.document?.name); break;
case 'save': console.log('Saved field:', e.uuid, e.saved); break;
case 'select': console.log('Selected field:', e.uuid); break;
}
};
<LsSigner
onSuccess={handleSignerEvent}
onFail={handleSignerEvent}
onChange={handleSignerEvent}
/>
Componente web:
const handleSignerEvent = (e) => {
switch (e.detail.eventType) {
case 'success': console.log('Signed:', e.detail.documentId); break;
case 'failure': console.log('Failed:', e.detail.failureReason, e.detail.error); break;
case 'ready': console.log('Ready:', e.detail.document?.name); break;
case 'save': console.log('Saved field:', e.detail.uuid, e.detail.saved); break;
case 'select': console.log('Selected field:', e.detail.uuid); break;
}
};
signer.addEventListener('signingSuccess', handleSignerEvent);
signer.addEventListener('signingFail', handleSignerEvent);
signer.addEventListener('fieldChange', handleSignerEvent);
Theming
Imposta il tema colore con la prop colour. Tutte le tonalità sono derivate automaticamente.
Colori disponibili
pink · blue · purple · indigo · teal · green · lightblue · burnt · aubergine · red · yellow · cyan · lime · trueGreen
Ommetti la prop per il blu predefinito.
<ls-signer colour="pink" ...></ls-signer>
<LsSigner colour="pink" ... />
La prop colour imposta un attributo data-ls-theme sulla radice del componente. Le proprietà CSS personalizzate definiscono una scala di tonalità da 10 a 100 per ogni colore:
| Tonalità | Uso |
|---|---|
| 10 | Sfondo chiaro, riempimenti delicati |
| 20 | Bordi delicati |
| 30 | Anelli di focus |
| 60 | Colore primario (pulsanti, link, stati attivi) |
| 70 | Stato hover |
| 80 | Accenti scuri/forti |
CSS personalizzato
Il componente espone proprietà CSS personalizzate che possono essere sovrascritte per personalizzare l'aspetto oltre il tema colore. Questo set di proprietà è attualmente limitato, contattaci per maggiori informazioni.
<ls-signer
style="--ls-font-family: 'Inter', sans-serif; --ls-color-primary-60: #e91e63;"
recipient-id="abc123"
private-key="key"
session-id="session"
></ls-signer>
Proprietà disponibili
| Proprietà | Predefinito | Descrizione |
|---|---|---|
--ls-font-family | 'IBM Plex Sans', sans-serif | Famiglia di font principale |
--ls-color-primary-10 a --ls-color-primary-100 | — | Scala completa del colore primario (sovrascrive il tema) |
--ls-color-error | #f64a44 | Colore stato errore |
--ls-color-error-light | #fff0f0 | Sfondo errore |
--ls-color-success | #46dbaa | Colore stato successo |
--ls-color-success-light | #effff9 | Sfondo successo |
--ls-color-warning | #fad232 | Colore stato avviso |
--ls-color-warning-light | #fffcef | Sfondo avviso |
--ls-color-border | #d8d9dc | Colore bordo predefinito |
--ls-color-border-subtle | #e0e2e5 | Colore bordo sottile |
--ls-color-bg-subtle | #f7f8fa | Colore sfondo sottile |
Nota: Per iniezione completa di CSS personalizzato (mirato agli elementi interni, sovrascrittura di dimensioni font, bordi arrotondati, spaziature, ecc.), è una funzionalità pianificata per il futuro. Per favore contattaci se sei interessato.
Internazionalizzazione
Il componente supporta 17 lingue con traduzioni incluse nel build. La lingua viene rilevata automaticamente dal browser. Un selettore di lingua integrato nell’interfaccia di firma permette al destinatario di cambiare lingua in qualsiasi momento.
Imposta l'attributo language per forzare una lingua specifica. Quando è fornito, il selettore di lingua integrato viene nascosto e il rilevamento browser viene bypassato.
<ls-signer language="fr" recipient-id="abc123" private-key="key" session-id="session"></ls-signer>
<LsSigner language="fr" recipientId="abc123" privateKey="key" sessionId="session" />
Ordine di priorità: prop language → lingua browser → inglese di fallback.
| Codice | Lingua | Codice | Lingua |
|---|---|---|---|
en | Inglese | nl | Olandese |
fr | Francese | fi | Finlandese |
bg | Bulgaro | it | Italiano |
es | Spagnolo | he | Ebraico |
de | Tedesco | sv | Svedese |
gs | Gaelico scozzese | cy | Gallese |
ar | Arabo | is | Islandese |
el | Greco | iw | Ebraico (legacy) |
pt | Portoghese | ||
ro | Romeno |
Versionamento CDN
L'URL CDN supporta sia latest che versioni bloccate:
<!-- Always get the most recent version (recommended) -->
<script type="module" src="https://cdn.legalesign.io/signer/latest/ls-signer.esm.js"></script>
<!-- Pin to a specific version -->
<script type="module" src="https://cdn.legalesign.io/signer/v1.1.7/ls-signer.esm.js"></script>
Consigliamo di usare latest — così la tua integrazione riceve automaticamente fix di bug, patch di sicurezza e nuove funzionalità. Usa una versione bloccata se devi fissarti su una release conosciuta durante un freeze QA o un rollout controllato. Vedi la storia completa delle versioni su npm per le versioni disponibili.
Esempio completo
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document Signing</title>
<script type="module" src="https://cdn.legalesign.io/signer/latest/ls-signer.esm.js"></script>
</head>
<body>
<ls-signer
recipient-id="abc123"
private-key="key"
session-id="session"
colour="teal"
></ls-signer>
<script>
const signer = document.querySelector('ls-signer');
signer.addEventListener('signingSuccess', (event) => {
console.log('Document signed:', event.detail.documentId);
window.location.href = '/thank-you';
});
signer.addEventListener('signingFail', (event) => {
console.error('Signing failed:', event.detail.failureReason, event.detail.error);
});
signer.addEventListener('fieldChange', (event) => {
if (event.detail.eventType === 'ready') {
console.log('Ready to sign:', event.detail.document.name);
}
});
</script>
</body>
</html>
Supporto browser
- Chrome/Edge (ultime versioni)
- Firefox (ultime versioni)
- Safari (ultime versioni)
- Browser mobile (iOS Safari, Chrome Mobile)
Changelog
| Versione | Data | Sommario |
|---|---|---|
| v1.1.7 | 20 Ott 2026 | Motivo documentCompleted; miglioramenti salvataggio campi; correzioni di posizionamento; migliorata cattura eventi failure |
| v1.1.0 | 22 Lug 2026 | Evento onChange / fieldChange; prop language; campi condizionali; salto automatico; QES |
| v1.0.12 | 20 Lug 2026 | Evento onChange / fieldChange con ready, save, select; valori failureReason; validazione regex |
| v1.0.11 | 15 Lug 2026 | Prop language; campi condizionali, dropdown, checkbox; input telefono; ordinamento campi |
| v1.0.6 | 9 Giu 2026 | Aggiunta prop branding |
| v1.0.3 | 15 Mag 2026 | Prop colour; proprietà CSS personalizzate; correzioni bug |
| v1.0.0 | 11 Mag 2026 | Prima release stabile |
Risorse
- Pacchetto NPM
- Widget Authorization
- Documentazione API GraphQL
- Migrazione dalla firma iframe
- Supporto