Install the lead form

Paste in the drawn form, change it for one page or set it up from JavaScript, or send leads from your own form.

Install: we draw the form#

Paste this where the form should appear. Copy it from the Install tab, We draw the form, so the key is already filled in:

html
<div data-subcontext-leadform></div>
<script src="https://js.subcontext.com/leadform-latest.js" data-key="lfk_YOUR_KEY" defer></script>
  • The <div> marks where the form goes. You can have more than one on a page.
  • The <script> loads the form code and carries your key. Include it once per page.
  • The form is the one designed on the Design tab.

Change the form for one page#

Add settings to the <div> to override the design on this page only. For example:

html
<div data-subcontext-leadform
     data-fields="first_name, email, phone"
     data-submit-label="Call me back"
     data-accent="#0a7f3b"
     data-utm-source="flyer"
     data-value-product-page="life-cover"></div>

Every setting is listed under Options.

Set it up from JavaScript#

For more control (your own fields, words, error messages, or code that runs after each send), start the form from JavaScript:

html
<div id="enquiry"></div>
<script>
  window.addEventListener('subcontext:leadform:ready', (event) => {
    const leadform = event.detail   // the same as window.Subcontext.leadform
    leadform.init({
      mode: 'head',                 // 'head' means "draw the form"
      target: '#enquiry',
      fields: ['first_name', 'email', 'phone', 'message'],
      onSuccess: (result) => console.log('sent', result)
    })
  })
</script>
<script src="https://js.subcontext.com/leadform-latest.js" data-key="lfk_YOUR_KEY" defer></script>

With a target, init() draws the form there. mode: 'head' does the same. Without a target, init() makes a form that draws nothing. See Install: your own form.

The script fires the subcontext:leadform:ready event once, as it loads, so add your listener before the script runs. A defer script runs after the page's other scripts, so the order above is safe. If your code might run after the form script, use a helper that handles both cases:

js
function whenLeadform(fn) {
  if (window.Subcontext?.leadform) fn(window.Subcontext.leadform)
  else window.addEventListener('subcontext:leadform:ready', (e) => fn(e.detail), { once: true })
}

Single-page apps#

The script draws every <div data-subcontext-leadform> on the page when it loads. It also redraws after page changes in sites built with Turbo. If your site adds the <div> later in some other way (React, Vue, another router), call this after adding it:

js
Subcontext.leadform.mountAll()

Each element is drawn only once, so you can call it again.

Install: your own form#

Keep your own HTML form. The script draws only the firm's consent wording and boxes into it, then sends the lead. This is the Install tab's Your own form snippet:

html
<form id="my-form">
  <input name="first_name" autocomplete="given-name">
  <input name="email" type="email" autocomplete="email">
  <textarea name="message"></textarea>
  <div id="my-form-consent"></div>
  <button>Send</button>
</form>
<script src="https://js.subcontext.com/leadform-latest.js" data-key="lfk_YOUR_KEY" defer></script>
<script>
  window.addEventListener('subcontext:leadform:ready', () => Subcontext.leadform.mountConsent('#my-form-consent'))
  document.querySelector('#my-form').addEventListener('submit', async (event) => {
    event.preventDefault()
    const data = new FormData(event.target)
    const values = {}
    for (const key of new Set(data.keys())) {
      const all = data.getAll(key)
      values[key] = all.length > 1 ? all : all[0]
    }
    const result = await Subcontext.createLead(values)
    if (!result.ok) console.log(result.message, result.fields)
  })
</script>

Each input's name is the field's key (for example first_name, email, or one of your own like product_page).

What the script does#

  • Loads the form's settings and consent wording as the page loads.
  • Checks the values before sending:
    • always: an email or a phone number is given, both are in a valid format, and nothing is too long;
    • if you list fields in init({ mode: 'headless', fields }): each listed field's required setting, choices, type and checks, as designed.
  • Drops answers to designed fields that shouldn't show (their "show if" rule says so).
  • Adds where the visitor came from, the consent answers, and which version of the consent wording they saw.
  • Solves the built-in bot check, if it is on, before sending.
  • Retries once if the connection drops, without ever creating the lead twice.

What it doesn't do#

  • Draw anything except the consent block.
  • Make the designed form's required fields required. Subcontext doesn't enforce them for your own form either. Mark them required in your form, or list them in fields.
  • Count views and starts for the Results tab.

Subcontext still checks any designed field you send: its choices, type, length and format. For example, sending topic: "Other" to a drop-down whose options don't include "Other" is refused with invalid.

Reading your form's values#

  • The loop in the snippet keeps every value of a repeated name, so a group of checkboxes sends every ticked box. That is a list, or a single value if only one was ticked. Subcontext accepts both. The shortcut Object.fromEntries(new FormData(form)) keeps only the last one.
  • A ticked checkbox sends "on". For a yes/no (checkbox) field, "on", "true", "yes" and "1" mean yes; "off", "false", "no" and "0" mean no. An unticked checkbox sends nothing.
  • The consent block's own inputs (named consent[...]) are sent as consent answers, not as lead details. So is a Cloudflare Turnstile token (cf-turnstile-response), if you use Turnstile.

From code only, with no form#

js
const result = await Subcontext.createLead({
  first_name: 'Ann',
  email: 'ann@example.com',
  phone: '07700 900123',
  message: 'Please call me about life cover.',
  product_page: 'life-cover',                 // any key of your own
  consent: { email: true },                   // box keys from consent()
  provenance: { utm_source: 'flyer', fbclid: 'abc' }
})
if (!result.ok) showErrors(result.message, result.fields)

To draw your own consent boxes instead of using mountConsent, read the wording with consent(). See Consent and example page 06.

Same settings for every send#

Subcontext.createLead has no settings of its own. If you want the same settings on every lead (provenance, hidden values, fields to check, your own messages), make a form with init() and send through it:

js
const form = Subcontext.leadform.init({
  mode: 'headless',
  fields: [{ key: 'email', required: true }],
  provenance: { utm_source: 'cover-calculator' },
  values: { product_page: 'life-cover' }
})
const result = await form.submit({ email: 'ann@example.com' })

Stuck, or something missing?

Get in touch and a person on the team will help.

Contact us