<bmx-document-signer>
Prepare a PDF for signing and sign it in the page: contracts, leases, consent forms, purchase orders, onboarding packs, anything with a line to sign on.
13 properties · 6 events · 16 methods · 5 parts
Example
A two-page tenancy agreement between fictional parties, with the tenant's and the landlord's fields already placed. Send it for signing, then sign as each of them.
Show markup
<div class="row" style="gap: 0.75rem; flex-wrap: wrap; align-items: center; margin-block-end: 0.75rem">
<label for="ex-sign-mode">Show</label>
<select id="ex-sign-mode">
<option value="prepare">Prepare (the letting agent)</option>
<option value="sign">Sign (the tenant, then the landlord)</option>
<option value="view">View</option>
</select>
</div>
<bmx-document-signer id="ex-sign" label="Tenancy agreement" src="assets/signing/tenancy-agreement.pdf" date-format="d MMMM yyyy"></bmx-document-signer>
<p class="note" id="ex-sign-out" role="status">A two-page tenancy agreement between fictional parties, with the tenant's and the landlord's fields already placed. Send it for signing, then sign as each of them.</p>
<script type="module">
await customElements.whenDefined('bmx-document-signer');
const el = document.getElementById('ex-sign');
const out = document.getElementById('ex-sign-out');
const mode = document.getElementById('ex-sign-mode');
el.envelope = {
id: 'lease-14-harbour-row',
title: 'Tenancy agreement - 14 Harbour Row',
signers: [
{ id: 'tenant', name: 'Priya Shah', email: 'priya.shah@example.com', role: 'Tenant', order: 1 },
{ id: 'landlord', name: 'Tom Reid', email: 'tom.reid@example.com', role: 'Landlord', order: 2 },
],
fields: [
{ id: 'pet', type: 'checkbox', page: 0, x: 48, y: 560, width: 12, height: 12, signer: 'tenant', required: false, label: 'Pet request' },
{ id: 'tenant-initials', type: 'initials', page: 0, x: 48, y: 604, width: 70, height: 26, signer: 'tenant' },
{ id: 'landlord-initials', type: 'initials', page: 0, x: 130, y: 604, width: 70, height: 26, signer: 'landlord' },
{ id: 'tenant-signature', type: 'signature', page: 1, x: 48, y: 194, width: 252, height: 40, signer: 'tenant' },
{ id: 'tenant-date', type: 'date', page: 1, x: 330, y: 214, width: 190, height: 18, signer: 'tenant' },
{ id: 'tenant-name', type: 'name', page: 1, x: 48, y: 256, width: 252, height: 18, signer: 'tenant' },
{ id: 'landlord-signature', type: 'signature', page: 1, x: 48, y: 330, width: 252, height: 40, signer: 'landlord' },
{ id: 'landlord-date', type: 'date', page: 1, x: 330, y: 350, width: 190, height: 18, signer: 'landlord' },
{ id: 'landlord-name', type: 'name', page: 1, x: 48, y: 392, width: 252, height: 18, signer: 'landlord' },
{ id: 'phone', type: 'text', page: 1, x: 48, y: 468, width: 252, height: 18, signer: 'tenant', required: false, label: 'Telephone' },
],
};
mode.addEventListener('change', () => (el.mode = mode.value));
el.addEventListener('bmxChange', e => {
if (e.detail.reason === 'send') {
mode.value = 'sign';
out.textContent = 'Sent. Priya signs first: fill in her fields, tick the agreement and choose Finish.';
}
});
el.addEventListener('bmxSignerComplete', e => {
const next = e.detail.envelope.signers.find(s => s.status === 'waiting');
out.textContent = next ? `${e.detail.signer.name} has signed. Now it is ${next.name}'s turn.` : `${e.detail.signer.name} has signed.`;
});
el.addEventListener('bmxComplete', () => {
mode.value = 'view';
el.mode = 'view';
out.textContent = 'Everyone has signed. Download the signed PDF: the values are on the pages and a signing certificate is added at the end.';
});
el.addEventListener('bmxDecline', e => (out.textContent = `${e.detail.signer.name} declined${e.detail.reason ? `: ${e.detail.reason}` : '.'}`));
</script>
WHAT IT DOES
- Prepare: add signers (name, email, role, order) and place fields for each on the pages - signature, initials, date signed, name, text, checkbox - by click, drag and keyboard; undo and redo.
- Sign: each signer, in order (or together, with the same order), is taken through their fields; draws or types a signature once and applies it to every signature field; agrees to sign electronically; finishes or declines with a reason.
- Out: the original PDF with every value stamped on its page (an incremental update - the original bytes are untouched at the start) and a signing certificate with each signer, their signature, the original file's SHA-256 and the activity log; the envelope as JSON for the audit trail.
The file and the signatures stay in the page. Nothing is sent anywhere; delivering the envelope to the next signer, and the legal standing of the process, are the host application's.
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
certificate |
certificate |
boolean |
true |
Add the signing certificate to the signed PDF. |
certificatePageSize |
certificate-page-size |
'a4' | 'letter' | 'first' |
'a4' |
The certificate's page size. |
dateFormat |
date-format |
string |
'd MMMM yyyy' |
How date fields are written unless a field says otherwise. |
envelope |
envelope |
Partial<BmxEnvelope> | string |
— | The envelope: signers, fields, values and log (an object, or its JSON). Kept up to date. |
fileName |
file-name |
string |
— | The name downloads are saved under, without the extension. Unset: the document's. |
label |
label |
string |
— | The element's accessible name. |
mode |
mode |
BmxDocumentSignerMode |
'prepare' |
Prepare fields, sign, or only look. |
penWidth |
pen-width |
number |
3 |
The pen width signatures are drawn with. |
requireConsent |
require-consent |
boolean |
true |
Ask signers to agree to sign electronically before they finish. |
signer |
signer |
string |
— | Who is signing (a signer's id). Unset: the first whose turn it is. |
src |
src |
string |
— | The PDF to open, by URL (same-origin credentials). Script can pass bytes or a Blob to open. |
strings |
strings |
Partial<BmxDocumentSignerStrings> | string |
— | Replacements for any of the wording (an object, or its JSON). |
zone |
zone |
string |
— | The time zone dates are written in (an IANA name; UTC when unset). |
Events
| Event | Detail | Description |
|---|---|---|
bmxChange |
BmxDocumentSignerChangeDetail |
Fired when the envelope changes: signers or fields edited, sent, filled in, finished, declined. |
bmxComplete |
BmxDocumentSignerDoneDetail |
Fired when the last signer finishes. |
bmxDecline |
BmxDocumentSignerDoneDetail |
Fired when a signer declines. |
bmxError |
BmxDocumentSignerErrorDetail |
Fired when a document cannot be opened or stamped, or the envelope belongs to another file. |
bmxLoad |
BmxDocumentSignerLoadDetail |
Fired when a document has opened. |
bmxSignerComplete |
BmxDocumentSignerDoneDetail |
Fired when a signer finishes. |
Methods
| Method | Signature | Description |
|---|---|---|
addField |
addField(field: Partial<BmxEnvelopeField> & { type: BmxEnvelopeFieldType; page: number; x: number; y: number; signer: string; }) => Promise<BmxEnvelopeField | BmxEnvelopeRefusal> |
Places a field while preparing (sizes default to the type's). |
addSigner |
addSigner(signer: Partial<BmxEnvelopeSigner> & { name: string; }) => Promise<BmxEnvelopeSigner | null> |
Adds a signer while preparing. |
decline |
decline(reason?: string) => Promise<BmxEnvelopeRefusal | null> |
Declines for the current signer. |
download |
download(kind?: "pdf" | "audit") => Promise<void> |
Saves the signed PDF or the audit trail. |
exportAudit |
exportAudit() => Promise<string> |
The envelope and the original file's fingerprint, as JSON. |
exportPdf |
exportPdf() => Promise<Blob | null> |
The signed PDF: values stamped on the original and the certificate added. |
finish |
finish(consent?: boolean) => Promise<BmxEnvelopeRefusal | null> |
Finishes for the current signer (with consent given here when asked for). Resolves with why it was refused, or null. |
getEnvelope |
getEnvelope() => Promise<BmxEnvelope> |
The envelope as it is now. |
goToField |
goToField(id: string) => Promise<void> |
Moves to a field and focuses it. |
open |
open(source: Uint8Array | ArrayBuffer | Blob | string, name?: string) => Promise<number> |
Opens a PDF: bytes, a Blob or File, or a URL. Resolves with the number of pages. |
redo |
redo() => Promise<void> |
Puts back what undo took. |
removeField |
removeField(id: string) => Promise<void> |
Removes a field while preparing. |
send |
send() => Promise<BmxEnvelopeRefusal | null> |
Sends the envelope for signing. Resolves with why it was refused, or null. |
setEnvelope |
setEnvelope(envelope: Partial<BmxEnvelope> | string) => Promise<void> |
Replaces the envelope. |
setValue |
setValue(fieldId: string, value: BmxEnvelopeValue | undefined) => Promise<BmxEnvelopeRefusal | null> |
Fills in a field for the signer whose turn it is. Resolves with why it was refused, or null. |
undo |
undo() => Promise<void> |
Takes back the last change while preparing. |
CSS shadow parts
| Part | Description |
|---|---|
dialog |
The signature dialog. |
field |
Each field on a page. |
pages |
The pages. |
sidebar |
Signers, fields and actions. |
toolbar |
The tools along the top. |
CSS custom properties
| Property | Description |
|---|---|
--bmx-document-signer-height |
The height of the pages area (and the sidebar beside it). |
--bmx-document-signer-ink |
The colour signatures are drawn in on screen. |
--bmx-document-signer-radius |
Corner radius of the frame. |
--bmx-document-signer-sidebar-width |
The sidebar's width beside the pages. |
--bmx-document-signer-signer-0 |
The first signer's colour, unless they name their own. Colours 0 to 7 are used in turn. |
--bmx-document-signer-signer-1 |
The second signer's colour. |
--bmx-document-signer-signer-2 |
The third signer's colour. |
--bmx-document-signer-signer-3 |
The fourth signer's colour. |
--bmx-document-signer-signer-4 |
The fifth signer's colour. |
--bmx-document-signer-signer-5 |
The sixth signer's colour. |
--bmx-document-signer-signer-6 |
The seventh signer's colour. |
--bmx-document-signer-signer-7 |
The eighth signer's colour. |