Example file

06-headless-code-only.html

No form: read consent(), draw your own boxes, and send from code through a handle with its own settings.

To try this page, download it, replace the placeholders and put it on a test page of your website. Opening the file from your computer won't work, because the embeds check the website address they're on.

06-headless-code-only.html · HTML Download
<!doctype html>
<!--
  From code, with no form: a two-step "Talk to an adviser" widget of your
  own. Your code keeps the handle from init(), so its settings (where they
  came from, the fields to check, your messages) apply to every send. It
  reads the firm's consent wording with consent(), draws its own boxes, and
  sends what was ticked.

  Replace lfk_YOUR_KEY with your form's key.
-->
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Lead form: from code</title>
  <style>
    #widget label { display: flex; gap: .5rem; align-items: flex-start; margin: .35rem 0; }
  </style>
</head>
<body>
  <h1>From code, no form</h1>
  <p>The script draws nothing here. This is a two-step widget of your own. It reads the firm's consent wording with
    <code>consent()</code>, draws its own boxes, and sends through a form handle from
    <code>init({ mode: 'headless', ... })</code>.</p>

  <div id="widget">
    <div id="step-1">
      <p><strong>What would you like to protect?</strong></p>
      <button type="button" data-cover="Life">My family (life cover)</button>
      <button type="button" data-cover="Income">My income</button>
    </div>
    <div id="step-2" hidden>
      <p><strong>Where should an adviser reach you?</strong></p>
      <input type="email" id="email" autocomplete="email" placeholder="name@example.com" aria-label="Email">
      <p id="consent-notice"></p>
      <div id="consent-boxes"></div>
      <p id="widget-error" role="alert"></p>
      <button type="button" id="send">Talk to an adviser</button>
    </div>
  </div>
  <!-- The chat after sending opens here, if the form has one. -->
  <div id="adviser-chat"></div>

  <!-- lfk_YOUR_KEY: your form's key (starts lfk_). Find it in Subcontext on the lead form's Install tab. -->
  <script src="https://js.subcontext.com/leadform-latest.js" data-key="lfk_YOUR_KEY" defer></script>
  <script>
    var coverType = null
    var boxes = [] // { key, optOut, input }

    window.addEventListener('subcontext:leadform:ready', async function (event) {
      var leadform = event.detail.init({
        mode: 'headless',
        // Checked before sending, the same way Subcontext checks them.
        fields: [
          { key: 'email', required: true },
          { key: 'cover_type', type: 'select', options: ['Life', 'Income'] }
        ],
        provenance: { utm_source: 'cover-calculator', utm_medium: 'web' },
        messages: { email: 'That email address looks wrong.' }
      })

      // { notice, opt_outs, marketing, versions }, or null
      var consent = await leadform.consent()
      if (consent) drawConsent(consent)

      document.querySelectorAll('[data-cover]').forEach(function (button) {
        button.addEventListener('click', function () {
          coverType = button.dataset.cover
          document.querySelector('#step-1').hidden = true
          document.querySelector('#step-2').hidden = false
          document.querySelector('#email').focus()
        })
      })

      document.querySelector('#send').addEventListener('click', async function () {
        var result = await leadform.submit({
          email: document.querySelector('#email').value,
          cover_type: coverType,
          calculator_result: 250000, // any key of your own is kept on the lead
          message: 'Asked for an adviser from the cover calculator.',
          consent: answers()
        })
        if (result.ok) {
          document.querySelector('#widget').textContent = 'Thanks, an adviser will be in touch.'
          await leadform.openChat(result, '#adviser-chat') // false if the form has no chat
        } else {
          document.querySelector('#widget-error').textContent = (result.fields && result.fields.email) || result.message
        }
      })
    })

    // Draws the firm's wording in your own markup. Opt-out boxes ("I'd rather
    // not...") and marketing boxes (one per channel, never ticked in advance).
    function drawConsent(consent) {
      document.querySelector('#consent-notice').textContent = consent.notice || ''
      var container = document.querySelector('#consent-boxes')
      var add = function (box, optOut) {
        var label = document.createElement('label')
        var input = document.createElement('input')
        input.type = 'checkbox'
        label.append(input, ' ', box.label)
        container.append(label)
        boxes.push({ key: box.key, optOut: optOut, input: input })
      }
      consent.opt_outs.forEach(function (box) { add(box, true) })
      if (consent.marketing) {
        var text = document.createElement('p')
        text.textContent = consent.marketing.text || ''
        container.append(text)
        consent.marketing.options.forEach(function (box) { add(box, false) })
      }
    }

    // Sends only ticked boxes. A ticked opt-out is false and a ticked
    // marketing box is true. An untouched box isn't sent, so it is never
    // recorded as a refusal.
    function answers() {
      var out = {}
      boxes.forEach(function (box) { if (box.input.checked) out[box.key] = !box.optOut })
      return out
    }
  </script>
</body>
</html>

Stuck, or something missing?

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

Contact us