Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.spitshake.io/llms.txt

Use this file to discover all available pages before exploring further.

Signing Form Web Component

The <docuseal-form> web component renders a fully functional signing form inside your application. Signers can view the document, fill in fields, draw signatures, and submit — all without leaving your page.

Quick start

Add the embed script and drop in the component:
<script src="https://your-app.com/js/docutrust-embed.js"></script>

<docuseal-form
  data-src="https://your-app.com/s/aB3kL9mNpQ"
></docuseal-form>
That is all you need to render a working signing form. The sections below cover every available attribute and event.

Attributes

The <docuseal-form> component accepts 39 data-* attributes to control behavior, pre-fill data, and customize the UI.
AttributeTypeDefaultDescription
data-srcstringrequiredSigning form URL. Format: https://your-app.com/s/SLUG where SLUG is the submitter’s unique signing slug.
data-emailstringPre-fill the signer’s email address. When provided, the email step is skipped.
data-namestringPre-fill the signer’s display name. When the submission uses quick_sign_mode: "confirmation_modal", this name is also used to auto-generate a cursive signature (Dancing Script font) and initials in the signing carousel.
data-rolestringTarget a specific submitter role (e.g., "Recipient", "Witness"). Required when the submission has multiple roles sharing the same email.
data-preview"true"Enable preview mode. The form renders all fields but disables submission. Useful for showing a read-only view of the document.
data-languagestringUI language code. Supported values: "en", "es", "fr", "de", "pt", "it", "nl", "ja", "zh", "ko", "ar", "he".
data-with-title"false""true"Set to "false" to hide the template title at the top of the form.
data-with-send-copy-button"false""true"Set to "false" to hide the “Send a copy” button that lets the signer email themselves a copy.
data-with-download-button"false""true"Set to "false" to hide the download button on the completion screen.
data-allow-to-resubmit"true""false"Set to "true" to allow the signer to resubmit the form after initial completion.
data-go-to-last"true"When set, the form automatically scrolls to the last incomplete field on load. Useful for returning signers who previously started filling out the form.
data-skip-fieldsstringComma-separated list of field names to skip. Skipped fields are hidden from the signer and not required. Example: "Internal Notes,Manager Approval".
data-valuesJSON stringPre-fill field values as a JSON object. Keys are field names, values are the pre-filled content. Example: '{"Full Name": "Jane Doe", "Company": "Acme Inc"}'.
data-metadataJSON stringAttach custom metadata to the submission as a JSON object. Metadata is returned in webhook payloads and API responses. Example: '{"customer_id": "cust_8472", "deal_id": "deal_291"}'.
data-readonly-fieldsstringComma-separated list of field names to render as read-only. The signer can see the value but cannot edit it. Example: "Contract Amount,Start Date".
data-completed-redirect-urlstringAbsolute URL to redirect the signer to after successful submission. The URL receives query parameters submitter_id and submission_id.
data-expand"true"Expand the form iframe to its full content height, eliminating internal scrolling. The form integrates seamlessly into the page layout.
data-minimize-first-step"true"Collapse the first step (usually email/name entry) into a compact bar. The signer clicks to expand it. Useful when you pre-fill email/name and want to reduce visual noise.
data-autoscroll"false""true"Set to "false" to disable automatic scrolling to the next field after the signer completes one.
data-external-idstringLink the signer to an external ID in your system. The value is stored on the submitter and returned in webhook payloads and API responses.
data-tokenstringJWT token for authentication. Use this instead of data-src when you generate a signing token server-side via POST /api/embed/token with audience: "form".
data-logostringURL to a custom logo image displayed at the top of the signing form. Overrides the account-level logo.
data-i18nJSON stringCustom i18n key overrides as a JSON object. Allows you to replace specific UI strings in the signing form. Example: '{"submit": "Confirm & Sign", "next": "Continue"}'.
data-with-decline"true"Set to "true" to show a “Decline” button, allowing the signer to decline the document. Fires the declined event when clicked.
data-with-field-names"false""true"Set to "false" to hide field labels/names above each input in the signing form.
data-with-field-placeholderstringShow placeholder text inside empty fields. The string value is used as the placeholder for text-type fields.
data-with-complete-button"false""true"Set to "false" to hide the complete/submit button. Useful when you want to control submission programmatically.
data-only-required-fields"true"When set to "true", only required fields are shown to the signer. Optional fields are hidden.
data-allow-typed-signature"false""true"Set to "false" to disable the typed signature option in the signature pad. Only drawn and uploaded signatures will be available.
data-signaturestringPre-fill the signature field with a base64-encoded image (data:image/png;base64,...), an image URL, or plain text (rendered as a typed signature in cursive). Directly sets the signature value — bypasses the carousel. For the 2-step QuickSign carousel UX, use data-name with confirmation_modal mode instead.
data-send-copy-email"false""true"Set to "false" to disable the option for the signer to send themselves a copy of the signed document via email.
data-order-as-on-page"true"When set to "true", fields are ordered by their position on the page (top to bottom, left to right) rather than the order defined in the template schema.
data-background-colorstringBackground color for the signing form as a HEX code (e.g., "#f3f4f6"). Overrides the default white background.
data-custom-cssstringCustom CSS rules injected into the signing form iframe. Allows overriding default styles for advanced branding. Example: "body { font-family: 'Inter', sans-serif; } .field-label { color: #1e3a5f; }".
data-completed-message-titlestringCustom title displayed on the completion screen after the signer submits. Replaces the default “Document signed” heading. Example: "Thank you for signing!".
data-completed-message-bodystringCustom body text displayed on the completion screen. Replaces the default completion message. Supports basic HTML. Example: "Your signed document will be emailed to you shortly.".
data-completed-button-titlestringCustom text for the button on the completion screen. Replaces the default button label. Example: "Return to Dashboard".
data-completed-button-urlstringCustom URL for the completion screen button. When set, clicking the button navigates to this URL instead of the default behavior. Example: "https://your-app.com/dashboard".
data-minimize"true"When set to "true", field panels are always minimized (collapsed). The signer clicks on a field area to expand it. Reduces visual clutter on documents with many fields.
data-autoscroll-fields"false""true"Alias for data-autoscroll. Set to "false" to disable automatic scrolling to the next field after the signer completes one.

QuickSign recipe (2-click signing)

Combine data-name on the embed with confirmation_modal mode on the submission for a 2-click signing experience: ESIGN consent → signature carousel → done. Step 1 — Create the submission (server-side):
POST /api/submissions
{
  "template_id": "tpl_7VQhP2tM9xA1kR8bN",
  "send_email": false,
  "quick_sign_mode": "confirmation_modal",
  "submitters": [{
    "email": "jane@example.com",
    "name": "Jane Smith",
    "role": "Client",
    "values": {
      "Company Name": "Acme Corp",
      "EIN": "12-3456789",
      "Effective Date": "2026-04-22"
    }
  }],
  "prefill_behavior": {
    "skip_if_prefilled": true,
    "editable_if_prefilled": false
  },
  "preferences": {
    "completed_redirect_url": "https://yourapp.com/done"
  }
}
Step 2 — Embed the signing form (client-side):
<docuseal-form
  data-src="https://spitshake.io/s/{slug_from_step_1}"
  data-name="Jane Smith"
  data-with-title="false"
  data-completed-redirect-url="https://yourapp.com/done"
/>
What the signer sees:
  1. ESIGN consent modal — “I Agree & Continue”
  2. Bottom-sheet carousel with 2 steps:
    • Signature — auto-generated in Dancing Script cursive from data-name, with REDRAW option
    • Initials — auto-generated from name initials (e.g. “JS”), with REDRAW option
  3. Each signature/initials value is applied to ALL fields of that type across all pages
  4. Pre-filled text fields render as read-only overlays on the document (visible but not editable)
  5. Redirect to completed_redirect_url after submission
data-name vs data-signature: Use data-name for the carousel UX (auto-generates cursive, signer can redraw). Use data-signature to directly pre-fill a specific signature image or text without the carousel. Both work — data-name gives the better interactive experience.
The carousel only triggers when ALL required non-signature fields have values. If required text fields are empty, the form falls back to field-by-field mode. Make sure to pre-fill all required fields via the values parameter.

Full HTML example

This example demonstrates every available attribute:
<script src="https://your-app.com/js/docutrust-embed.js"></script>

<docuseal-form
  id="signing-form"
  data-src="https://your-app.com/s/aB3kL9mNpQ"
  data-email="jane.doe@example.com"
  data-name="Jane Doe"
  data-role="Recipient"
  data-external-id="usr_9f84b2a1"
  data-token="eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxNDIiLCJpc3MiOiJkb2N1dHJ1c3QiLCJhdWQiOiJmb3JtIn0.xyz789"
  data-logo="https://your-app.com/assets/logo.png"
  data-language="en"
  data-preview="false"
  data-with-title="true"
  data-with-send-copy-button="true"
  data-with-download-button="true"
  data-with-decline="true"
  data-with-field-names="true"
  data-with-field-placeholder="Enter value here"
  data-with-complete-button="true"
  data-only-required-fields="false"
  data-allow-to-resubmit="false"
  data-allow-typed-signature="true"
  data-go-to-last="true"
  data-autoscroll="true"
  data-expand="true"
  data-minimize-first-step="true"
  data-order-as-on-page="false"
  data-send-copy-email="true"
  data-background-color="#ffffff"
  data-custom-css="body { font-family: 'Inter', sans-serif; } .field-label { color: #1e3a5f; }"
  data-completed-message-title="Thank you for signing!"
  data-completed-message-body="Your signed document will be emailed to you shortly."
  data-completed-button-title="Return to Dashboard"
  data-completed-button-url="https://your-app.com/dashboard"
  data-minimize="false"
  data-autoscroll-fields="true"
  data-skip-fields="Internal Notes"
  data-readonly-fields="Contract Amount,Start Date"
  data-completed-redirect-url="https://your-app.com/signing-complete"
  data-signature="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
  data-values='{
    "Full Name": "Jane Doe",
    "Email": "jane.doe@example.com",
    "Company": "Acme Inc",
    "Title": "VP of Operations",
    "Date": "2026-04-08"
  }'
  data-metadata='{
    "customer_id": "cust_8472",
    "deal_id": "deal_291",
    "plan": "enterprise",
    "source": "onboarding_flow"
  }'
  data-i18n='{
    "submit": "Confirm & Sign",
    "next": "Continue",
    "decline": "Decline to Sign",
    "type_here": "Start typing..."
  }'
></docuseal-form>

Events

The <docuseal-form> component emits DOM custom events that you can listen to with addEventListener. Every event provides a detail property on the event object with relevant data.

init

Fired when the web component is initialized and the iframe begins loading.
document.getElementById('signing-form').addEventListener('init', function (event) {
  console.log('Form iframe is loading');
});
Event detail: null

load

Fired when the iframe has loaded and the form is ready to render.
document.getElementById('signing-form').addEventListener('load', function (event) {
  console.log('Form iframe loaded');
});
Event detail: null

loaded

Fired when the form content has fully rendered and is interactive.
document.getElementById('signing-form').addEventListener('loaded', function (event) {
  console.log('Form ready:', event.detail);
});
Event detail:
{
  "submitter_id": 142,
  "submission_id": 89,
  "template_id": 15,
  "template_name": "Employment Agreement",
  "role": "Recipient",
  "status": "opened",
  "fields": [
    {
      "name": "Full Name",
      "type": "text",
      "required": true,
      "value": "Jane Doe"
    },
    {
      "name": "Signature",
      "type": "signature",
      "required": true,
      "value": null
    },
    {
      "name": "Date",
      "type": "date",
      "required": true,
      "value": "2026-04-08"
    },
    {
      "name": "Contract Amount",
      "type": "text",
      "required": false,
      "value": "$150,000"
    }
  ]
}

completed

Fired when the signer successfully submits the form.
document.getElementById('signing-form').addEventListener('completed', function (event) {
  var data = event.detail;
  console.log('Submission completed');
  console.log('Submitter ID:', data.submitter_id);
  console.log('Documents:', data.documents);
});
Event detail:
{
  "submitter_id": 142,
  "submission_id": 89,
  "template_id": 15,
  "role": "Recipient",
  "email": "jane.doe@example.com",
  "name": "Jane Doe",
  "status": "completed",
  "completed_at": "2026-04-08T14:32:18.000Z",
  "audit_log_url": "https://your-app.com/submissions/89/audit_log",
  "documents": [
    {
      "name": "Employment Agreement - Signed",
      "url": "https://your-app.com/blobs/proxy/eyJfcm...",
      "content_type": "application/pdf",
      "size": 284716
    }
  ],
  "values": {
    "Full Name": "Jane Doe",
    "Email": "jane.doe@example.com",
    "Company": "Acme Inc",
    "Title": "VP of Operations",
    "Date": "2026-04-08",
    "Signature": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
  },
  "metadata": {
    "customer_id": "cust_8472",
    "deal_id": "deal_291",
    "plan": "enterprise",
    "source": "onboarding_flow"
  }
}

declined

Fired when the signer declines to sign the document.
document.getElementById('signing-form').addEventListener('declined', function (event) {
  var data = event.detail;
  console.log('Signer declined:', data.reason);
});
Event detail:
{
  "submitter_id": 142,
  "submission_id": 89,
  "template_id": 15,
  "role": "Recipient",
  "email": "jane.doe@example.com",
  "name": "Jane Doe",
  "status": "declined",
  "declined_at": "2026-04-08T14:35:02.000Z",
  "reason": "Terms not acceptable"
}

field-value

Fired each time the signer fills in or changes a field value.
document.getElementById('signing-form').addEventListener('field-value', function (event) {
  var data = event.detail;
  console.log('Field changed:', data.name, '=', data.value);
});
Event detail:
{
  "submitter_id": 142,
  "submission_id": 89,
  "field_name": "Full Name",
  "field_type": "text",
  "value": "Jane Doe",
  "page": 1,
  "completed_fields": 3,
  "total_fields": 7
}

docutrust:resize

Fired when the form content height changes. Used internally by the web component to auto-resize the iframe. If you use a direct iframe, listen for this event to sync the iframe height. Event detail:
{
  "height": 1247
}

React integration

Use the web component directly in React with a ref for event handling:
import { useEffect, useRef, useCallback } from 'react';

function SigningForm({ slug, signerEmail, signerName }) {
  const formRef = useRef(null);

  const handleCompleted = useCallback((event) => {
    const data = event.detail;
    console.log('Submission completed:', data.submission_id);
    console.log('Submitter:', data.submitter_id);
    console.log('Documents:', data.documents);
    // Navigate to a thank-you page or update your UI
    window.location.href = `/submissions/${data.submission_id}/success`;
  }, []);

  const handleDeclined = useCallback((event) => {
    const data = event.detail;
    console.log('Signer declined:', data.reason);
    // Show a message or redirect
  }, []);

  const handleFieldValue = useCallback((event) => {
    const data = event.detail;
    console.log(`Field "${data.field_name}" set to:`, data.value);
    console.log(`Progress: ${data.completed_fields}/${data.total_fields}`);
  }, []);

  useEffect(() => {
    const el = formRef.current;
    if (!el) return;

    el.addEventListener('completed', handleCompleted);
    el.addEventListener('declined', handleDeclined);
    el.addEventListener('field-value', handleFieldValue);

    return () => {
      el.removeEventListener('completed', handleCompleted);
      el.removeEventListener('declined', handleDeclined);
      el.removeEventListener('field-value', handleFieldValue);
    };
  }, [handleCompleted, handleDeclined, handleFieldValue]);

  return (
    <docuseal-form
      ref={formRef}
      data-src={`https://your-app.com/s/${slug}`}
      data-email={signerEmail}
      data-name={signerName}
      data-role="Recipient"
      data-external-id="usr_9f84b2a1"
      data-logo="https://your-app.com/assets/logo.png"
      data-language="en"
      data-with-title="true"
      data-with-send-copy-button="true"
      data-with-download-button="true"
      data-with-decline="true"
      data-with-field-names="true"
      data-with-field-placeholder="Enter value here"
      data-with-complete-button="true"
      data-only-required-fields="false"
      data-allow-to-resubmit="false"
      data-allow-typed-signature="true"
      data-go-to-last="true"
      data-expand="true"
      data-autoscroll="true"
      data-order-as-on-page="false"
      data-send-copy-email="true"
      data-background-color="#ffffff"
      data-custom-css="body { font-family: 'Inter', sans-serif; } .field-label { color: #1e3a5f; }"
      data-completed-message-title="Thank you for signing!"
      data-completed-message-body="Your signed document will be emailed to you shortly."
      data-completed-button-title="Return to Dashboard"
      data-completed-button-url="https://your-app.com/dashboard"
      data-minimize="false"
      data-autoscroll-fields="true"
      data-completed-redirect-url="https://your-app.com/signing-complete"
      data-values={JSON.stringify({
        'Full Name': signerName,
        'Email': signerEmail,
        'Company': 'Acme Inc',
        'Title': 'VP of Operations',
        'Date': '2026-04-08'
      })}
      data-metadata={JSON.stringify({
        customer_id: 'cust_8472',
        deal_id: 'deal_291',
        plan: 'enterprise',
        source: 'react_app'
      })}
      data-i18n={JSON.stringify({
        submit: 'Confirm & Sign',
        next: 'Continue'
      })}
    />
  );
}

export default SigningForm;
Remember to include the embed script in your HTML. In React, add it to your index.html or load it dynamically:
<script src="https://your-app.com/js/docutrust-embed.js"></script>

Vue integration

<template>
  <docuseal-form
    ref="formEl"
    :data-src="`https://your-app.com/s/${slug}`"
    :data-email="signerEmail"
    :data-name="signerName"
    data-role="Recipient"
    data-external-id="usr_9f84b2a1"
    data-logo="https://your-app.com/assets/logo.png"
    data-language="en"
    data-with-title="true"
    data-with-send-copy-button="true"
    data-with-download-button="true"
    data-with-decline="true"
    data-with-field-names="true"
    data-with-field-placeholder="Enter value here"
    data-with-complete-button="true"
    data-only-required-fields="false"
    data-allow-to-resubmit="false"
    data-allow-typed-signature="true"
    data-expand="true"
    data-autoscroll="true"
    data-order-as-on-page="false"
    data-send-copy-email="true"
    data-background-color="#ffffff"
    data-custom-css="body { font-family: 'Inter', sans-serif; }"
    data-completed-message-title="Thank you for signing!"
    data-completed-message-body="Your signed document will be emailed to you shortly."
    data-completed-button-title="Return to Dashboard"
    data-completed-button-url="https://your-app.com/dashboard"
    data-minimize="false"
    data-autoscroll-fields="true"
    :data-values="JSON.stringify({ 'Full Name': signerName, 'Email': signerEmail, 'Company': 'Acme Inc' })"
    :data-metadata="JSON.stringify({ customer_id: customerId, source: 'vue_app' })"
    :data-i18n="JSON.stringify({ submit: 'Confirm & Sign', next: 'Continue' })"
    :data-completed-redirect-url="redirectUrl"
  />
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const props = defineProps({
  slug: { type: String, required: true },
  signerEmail: { type: String, required: true },
  signerName: { type: String, required: true },
  customerId: { type: String, default: '' },
  redirectUrl: { type: String, default: '' }
});

const emit = defineEmits(['completed', 'declined', 'fieldValue']);

const formEl = ref(null);

function onCompleted(event) {
  emit('completed', event.detail);
}

function onDeclined(event) {
  emit('declined', event.detail);
}

function onFieldValue(event) {
  emit('fieldValue', event.detail);
}

onMounted(() => {
  const el = formEl.value;
  if (!el) return;
  el.addEventListener('completed', onCompleted);
  el.addEventListener('declined', onDeclined);
  el.addEventListener('field-value', onFieldValue);
});

onUnmounted(() => {
  const el = formEl.value;
  if (!el) return;
  el.removeEventListener('completed', onCompleted);
  el.removeEventListener('declined', onDeclined);
  el.removeEventListener('field-value', onFieldValue);
});
</script>

Pre-filling fields

Use data-values to pre-populate form fields. The JSON object maps field names (as defined in the template) to their values.
<docuseal-form
  data-src="https://your-app.com/s/aB3kL9mNpQ"
  data-email="jane.doe@example.com"
  data-name="Jane Doe"
  data-signature="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
  data-values='{
    "Full Name": "Jane Doe",
    "Email": "jane.doe@example.com",
    "Company": "Acme Inc",
    "Title": "VP of Operations",
    "Start Date": "2026-04-08",
    "Salary": "150000",
    "Department": "Engineering",
    "Office Location": "San Francisco"
  }'
></docuseal-form>
Use data-signature to pre-fill the signature field. Accepted formats: a base64-encoded image (data:image/png;base64,...), an HTTPS image URL, or plain text that renders as a typed signature.
Supported field types for pre-fill:
Field TypeValue FormatExample
textString"Jane Doe"
dateISO date string"2026-04-08"
numberNumeric string"150000"
checkbox"true" or "false""true"
selectOption value string"Option B"
radioOption value string"Yes"
phoneE.164 format"+14155551234"
cellsString (one char per cell)"ABC123"
Signature, initials, image, file, and stamp fields cannot be pre-filled via data-values. These require the signer to provide them interactively.

Redirect after completion

Use data-completed-redirect-url to send the signer to a custom page after they submit. DocuTrust appends query parameters to the URL so your application can identify the completed submission.
<docuseal-form
  data-src="https://your-app.com/s/aB3kL9mNpQ"
  data-completed-redirect-url="https://your-app.com/signing-complete"
></docuseal-form>
The redirect URL will receive these query parameters:
https://your-app.com/signing-complete?submitter_id=142&submission_id=89
ParameterDescription
submitter_idThe ID of the submitter who just completed signing
submission_idThe ID of the parent submission

postMessage events

When the signing form is embedded in an iframe (either via the web component or a raw <iframe>), the form communicates with the parent window via postMessage. Listen for these events to react to signing lifecycle changes without polling.
window.addEventListener('message', (event) => {
  if (!event.data?.type?.startsWith('docutrust:')) return

  switch (event.data.type) {
    case 'docutrust:completed':
      console.log('Signed!', event.data.detail)
      break
    case 'docutrust:declined':
      console.log('Declined', event.data.detail)
      break
  }
})
EventFired whenPayload
docutrust:loadedThe signing form iframe has loaded and is ready.{ submitter: "slug" }
docutrust:completedThe signer has submitted all fields successfully.{ submitter: "slug" }
docutrust:declinedThe signer declined to sign.{ submitter: "slug" }
docutrust:field-valueA field value changed (useful for live sync).{ field_uuid, value }
docutrust:resizeThe iframe content height changed (for auto-sizing).{ height: 1200 }
Use docutrust:completed as the trigger for your backend workflow (e.g. marking the agreement as signed, dispatching follow-up emails). This fires before any redirect, so you can act on it immediately.