Example file
05-headless-own-form.html
Your own HTML form with the firm's consent block, createLead, field errors and the chat after the form.
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.
<!doctype html>
<!--
Your own form: you keep your own HTML form and styles. The script draws
only the firm's consent block into it (mountConsent), checks and sends the
lead (Subcontext.createLead), shows each field's error next to its input,
and opens the chat after the form if it has one (openChat). This is the
Install tab's "Your own form" snippet, filled out.
Replace lfk_YOUR_KEY with your form's key. Each input's name is the
field's key (first_name, email, or one of your own).
-->
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Lead form: your own form</title>
<style>
#my-form { display: grid; gap: .75rem; max-width: 32rem; }
#my-form label { display: grid; gap: .25rem; }
#my-form fieldset label { display: flex; gap: .5rem; }
#my-form .error { color: #b91c1c; }
</style>
</head>
<body>
<h1>Your own form</h1>
<p>You keep your own form and styles. The script draws the firm's consent wording and boxes into it
(<code>mountConsent</code>), checks and sends the lead (<code>Subcontext.createLead</code>), and opens the chat
after the form, if it has one (<code>openChat</code>).</p>
<form id="my-form" novalidate>
<label>First name <input name="first_name" autocomplete="given-name"></label>
<label>Email <input name="email" type="email" autocomplete="email"></label>
<label>Phone <input name="phone" type="tel" autocomplete="tel"></label>
<fieldset>
<legend>Interested in</legend>
<label><input type="checkbox" name="interests" value="Life cover"> Life cover</label>
<label><input type="checkbox" name="interests" value="Income protection"> Income protection</label>
<label><input type="checkbox" name="interests" value="Critical illness"> Critical illness</label>
</fieldset>
<label>Message <textarea name="message" rows="4"></textarea></label>
<!-- The firm's consent wording and boxes are drawn here. -->
<div id="my-form-consent"></div>
<p id="form-message" role="alert"></p>
<button>Send</button>
</form>
<!-- The chat after the form opens here, if the form has one. -->
<div id="my-form-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 form = document.querySelector('#my-form')
window.addEventListener('subcontext:leadform:ready', function () {
Subcontext.leadform.mountConsent('#my-form-consent')
})
// Shows the result's message, and each field's message next to its input.
function showErrors(message, fields) {
form.querySelectorAll('.error').forEach(function (node) { node.remove() })
form.querySelectorAll('[aria-invalid]').forEach(function (node) { node.removeAttribute('aria-invalid') })
document.querySelector('#form-message').textContent = message
Object.keys(fields || {}).forEach(function (key) {
var input = form.elements[key]
if (!input) return
// A group of checkboxes: put the message after its fieldset.
var target = input.length && !input.tagName ? input[0].closest('fieldset') : input
var error = document.createElement('span')
error.className = 'error'
error.textContent = fields[key]
target.setAttribute('aria-invalid', 'true')
target.after(error)
})
}
form.addEventListener('submit', async function (event) {
event.preventDefault()
// Keep every value of a repeated name. Object.fromEntries would keep only the last box ticked.
var data = new FormData(form)
var values = {}
new Set(data.keys()).forEach(function (key) {
var all = data.getAll(key)
values[key] = all.length > 1 ? all : all[0]
})
var button = form.querySelector('button')
button.disabled = true
var result = await Subcontext.createLead(values)
button.disabled = false
if (result.ok) {
// 'held' means the campaign's rules held it for review. Treat it as a success.
var thanks = document.createElement('p')
thanks.textContent = 'Thanks, we will be in touch.'
form.replaceWith(thanks)
await Subcontext.leadform.openChat(result, '#my-form-chat') // false if the form has no chat
} else {
showErrors(result.message, result.fields)
}
})
</script>
</body>
</html>