Integrar el firmante de Legalesign en su sitio web
El componente Firmante requiere activación. Contacte con soporte para habilitarlo para su equipo.
Versión actual: v1.1.7 — registro de cambios
El firmante de Legalesign es un componente web independiente de la plataforma que ofrece una experiencia completa y fluida para la firma de documentos desde su propia aplicación. Funciona con HTML puro, React, Vue, Angular o cualquier framework web.
Inserte este componente donde sus usuarios necesiten firmar documentos — dentro de un CRM, portal de clientes o cualquier aplicación interna que renderice HTML.
Instalación
Cárguelo directamente desde el CDN (no se requiere instalación):
<script type="module" src="https://cdn.legalesign.io/signer/latest/ls-signer.esm.js"></script>
Instalación en React
Instale mediante un gestor de paquetes:
npm install legalesign-signer
# or
pnpm add legalesign-signer
Integración Básica
HTML y 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 requiere react y react-dom (v18 o v19) como dependencias pares.
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>
Si utiliza Vue con Vite, añada isCustomElement: (tag) => tag.startsWith('ls-') a la configuración del plugin Vue para suprimir advertencias de elementos desconocidos.
Vue 3 convierte a minúsculas los nombres de eventos en elementos personalizados, por lo que @signingSuccess no funcionará. Use addEventListener en la referencia al elemento como se muestra arriba.
Envuelva <ls-signer> en <ClientOnly> para evitar errores SSR. Añada la configuración para elementos personalizados en nuxt.config.ts:
export default defineNuxtConfig({
vue: {
compilerOptions: {
isCustomElement: (tag) => tag.startsWith('ls-'),
},
},
});
Autenticación
El componente firmante requiere un token de corta duración desde su backend. Hay dos opciones:
- GraphQL
generateComponentToken— Llame concomponent: LS_SIGNERy ya sea unrecipientIdosessionIden el ámbito del firmante (proporcione uno, no ambos). - REST API — Llame a
GET /signer/{signerId}/component-token/con su clave API.
Ambos retornan el token y sessionId necesarios para el componente. Consulte Autorización de Widget para el flujo completo del token en el servidor.
Opción 1: GraphQL (Node.js)
Usando recipientId (lo más común — úselo cuando conozca al destinatario pero aún no tenga sesión):
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;
Alternativamente, si ya tiene un sessionId de una llamada previa:
variables: {
input: {
component: 'LS_SIGNER',
signer: { sessionId: '<session-id>' }
}
}
Opción 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();
Pase token como private-key y sessionId como session-id al componente.
Atributos Requeridos
| Atributo | Tipo | Descripción |
|---|---|---|
recipient-id | string | Identificador del destinatario (base64, prefijo rec, o UUID) |
private-key | string | Token retornado por generateComponentToken |
session-id | string | ID de sesión retornado por generateComponentToken |
Atributos Opcionales
| Atributo | Tipo | Predeterminado | Descripción |
|---|---|---|---|
colour | string | blue | Nombre del color del tema (ver Theming) |
style | string | `` | Alteraciones de estilo (ver Custom CSS) |
branding | boolean | true | Mostrar branding de Legalesign. Configure false para retirarlo. |
language | string | — | Forzar un idioma específico y ocultar el selector de idioma (ver Internationalisation) |
Eventos
| Propiedad React | Evento del componente web | eventType | Cuándo |
|---|---|---|---|
onSuccess | signingSuccess | "success" | Documento firmado exitosamente |
onFail | signingFail | "failure" | Firma fallida, rechazada, expiró, cancelada, eliminada, retirada o ya completada en otro lugar |
onChange | fieldChange | "ready" | Documento e imágenes completamente cargados |
onChange | fieldChange | "save" | Un valor de campo fue guardado |
onChange | fieldChange | "select" | Un campo fue seleccionado o enfocado |
onSuccess / signingSuccess
Se dispara cuando el destinatario firma el documento con éxito.
{
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
Se dispara cuando la firma falla — ya sea por rechazo del documento o error durante el proceso de firma (ej. error de red, sesión expirada, conflicto de estado 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 | El state del documento es "expired" o la fecha de expires está en el pasado |
sessionExpired | La API retornó 401 o 403 al cargar el documento |
cancelled | El state del documento es "cancelled" |
deleted | La bandera is_deleted del documento es true |
rejected | El destinatario rechazó el documento (is_rejected es true) |
removed | La API retornó 404 — el documento ya no existe |
documentCompleted | La API de firma retornó completed — el documento ya fue firmado, probablemente en otro navegador o dispositivo. El componente muestra un mensaje informativo al destinatario en lugar de un error. |
signingError | Cualquier otro error durante la carga o 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
Los tres valores de eventType comparten el mismo evento. Use eventType para distinguir.
eventType: "ready"
Se dispara una sola vez cuando el documento y todas las imágenes de página están completamente cargadas y la interfaz de firma está lista para interactuar.
{
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"
Se dispara después de que un valor de campo haya sido guardado en el servidor.
{
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"
Se dispara cuando un campo es seleccionado o enfocado — desencadenado por un click del usuario, navegación por teclado, avance automático, o interacción con la barra lateral.
{
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);
}
});
Propiedades del Campo
El objeto field incluido en los eventos save y select contiene las siguientes propiedades:
| Propiedad | Tipo | Descripción |
|---|---|---|
uuid | string | Identificador único del campo |
fieldtype | string | Tipo de campo (ej. "text", "signature", "date", "checkbox") |
value | string | Valor actual del campo |
state | boolean | Si el campo ha sido guardado con éxito |
optional | boolean | Si el campo es opcional |
page | number | Número de página donde aparece el campo |
label | string | Etiqueta del campo (si está configurada) |
validation | number | Código de tipo de validación |
logicaction | string | Tipo de acción lógica ("1" = radio, "2" = suma, "3" = condicional) |
logicgroup | string | Identificador del grupo lógico |
mapto | string | Grupo objetivo para la lógica (campos controladores) |
auto | boolean | Si el campo se autocompleta |
dirty | boolean | Si el campo tiene cambios locales no guardados |
Props de React
El componente React usa props en camelCase y callbacks en lugar de eventos DOM:
| Prop | Tipo | Requerido | Descripción |
|---|---|---|---|
recipientId | string | ✅ | Identificador del destinatario |
privateKey | string | ✅ | Clave privada de la mutación generateComponentToken |
sessionId | string | ✅ | Identificador de sesión |
colour | LsSignerColour | ❌ | Color del tema |
branding | boolean | ❌ | Mostrar branding de Legalesign. Por defecto true. |
language | string | ❌ | Forzar un idioma específico (ver Internationalisation) |
onSuccess | (data: { eventType: 'success'; documentId: string; recipientId: string }) => void | ❌ | Llamado al firmar exitosamente |
onFail | (data: { eventType: 'failure'; failureReason: FailureReason; error: string; documentId?: string; recipientId: string }) => void | ❌ | Llamado al fallar la firma |
onChange | (data: { eventType: 'ready' | 'save' | 'select'; document?: DocumentSummary; uuid?: string; saved?: boolean; field?: Record<string, any> }) => void | ❌ | Llamado en eventos de campo y cuando el documento está listo |
Manejador universal (depuración y prototipado)
Dado que cada evento incluye eventType, puede enlazar una única función a todos los eventos:
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
Configura un tema de color con la prop colour. Todos los tonos se derivan automáticamente.
Colores disponibles
pink · blue · purple · indigo · teal · green · lightblue · burnt · aubergine · red · yellow · cyan · lime · trueGreen
Omitir la prop para obtener el azul por defecto.
<ls-signer colour="pink" ...></ls-signer>
<LsSigner colour="pink" ... />
La prop colour establece un atributo data-ls-theme en la raíz del componente. Las propiedades CSS personalizadas definen una escala de tonos de 10 a 100 para cada color:
| Tono | Uso |
|---|---|
| 10 | Fondos claros, rellenos sutiles |
| 20 | Bordes sutiles |
| 30 | Anillos de foco |
| 60 | Color primario (botones, enlaces, estados activos) |
| 70 | Estado hover |
| 80 | Acentos oscuros/fuertes |
CSS personalizado
El componente expone propiedades CSS personalizadas que pueden sobrescribirse para personalizar la apariencia más allá del tema de color. Este conjunto de propiedades es limitado actualmente; contáctenos para más.
<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>
Propiedades disponibles
| Propiedad | Predeterminado | Descripción |
|---|---|---|
--ls-font-family | 'IBM Plex Sans', sans-serif | Familia tipográfica principal |
--ls-color-primary-10 a --ls-color-primary-100 | — | Escala completa de color primario (sobrescribe tema) |
--ls-color-error | #f64a44 | Color para estado de error |
--ls-color-error-light | #fff0f0 | Fondo de error |
--ls-color-success | #46dbaa | Color para estado de éxito |
--ls-color-success-light | #effff9 | Fondo de éxito |
--ls-color-warning | #fad232 | Color para estado de advertencia |
--ls-color-warning-light | #fffcef | Fondo de advertencia |
--ls-color-border | #d8d9dc | Color predeterminado de borde |
--ls-color-border-subtle | #e0e2e5 | Color sutil de borde |
--ls-color-bg-subtle | #f7f8fa | Color sutil de fondo |
Nota: Para inyección completa de CSS personalizado (dirigido a elementos internos directamente, sobrescribiendo tamaños de fuente, radios de borde, espaciados, etc.), esta es una función planificada futura. Por favor contacte con nosotros si está interesado.
Internacionalización
El componente soporta 17 idiomas con traducciones incluidas en la compilación. El idioma se detecta automáticamente desde el navegador. Un selector de idioma integrado en la UI de firma permite al destinatario cambiar el idioma en cualquier momento.
Configure el atributo language para forzar un idioma específico. Cuando se proporciona, el selector integrado de idiomas se oculta y se omite la detección del navegador.
<ls-signer language="fr" recipient-id="abc123" private-key="key" session-id="session"></ls-signer>
<LsSigner language="fr" recipientId="abc123" privateKey="key" sessionId="session" />
Orden de prioridad: prop language → idioma del navegador → inglés por defecto.
| Código | Idioma | Código | Idioma |
|---|---|---|---|
en | Inglés | nl | Neerlandés |
fr | Francés | fi | Finés |
bg | Búlgaro | it | Italiano |
es | Español | he | Hebreo |
de | Alemán | sv | Sueco |
gs | Gaélico escocés | cy | Galés |
ar | Árabe | is | Islandés |
el | Griego | iw | Hebreo (legado) |
pt | Portugués | ||
ro | Rumano |
Versionado CDN
La URL del CDN soporta números de versión latest y fijos:
<!-- 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>
Recomendamos usar latest — así su integración recibirá automáticamente correcciones de errores, parches de seguridad y nuevas funciones. Use una versión fija si necesita un lanzamiento conocido durante un período de congelación QA o despliegue controlado. Vea el historial completo de versiones en npm para las versiones disponibles.
Ejemplo 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>
Soporte de Navegadores
- Chrome/Edge (última versión)
- Firefox (última versión)
- Safari (última versión)
- Navegadores móviles (iOS Safari, Chrome Mobile)
Registro de Cambios
| Versión | Fecha | Resumen |
|---|---|---|
| v1.1.7 | 20 Oct 2026 | Motivo documentCompleted; mejoras en guardado de campo; correcciones de posicionamiento; mejor captura de eventos de fallo |
| v1.1.0 | 22 Jul 2026 | Evento onChange / fieldChange; prop language; campos condicionales; salto automático; QES |
| v1.0.12 | 20 Jul 2026 | Evento onChange / fieldChange con ready, save, select; valores de failureReason; validación con regex |
| v1.0.11 | 15 Jul 2026 | Prop language; campos condicionales, desplegables, checkbox; entrada telefónica; orden de campos |
| v1.0.6 | 9 Jun 2026 | Prop branding añadida |
| v1.0.3 | 15 May 2026 | Prop colour; propiedades CSS personalizadas; corrección de errores |
| v1.0.0 | 11 May 2026 | Lanzamiento estable inicial |