v2.6.0

<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

PropertyAttributeTypeDefaultDescription
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

EventDetailDescription
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

MethodSignatureDescription
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

PartDescription
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

PropertyDescription
--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.