Building a Form

Forms live under Design → Forms. Open the Design tab in the rail, pick Forms from the section list at the top of the left panel — its blurb reads Lead-capture forms — and the panel lists every form in your workspace with a search box, an A–Z sort control and a New form button. Selecting a form opens it on the canvas with two tabs: Form Details, which is everything on this page, and Submissions.

Settings → Forms shows the same list read-only, with a publish indicator on each row and an Open form link. It is a good place to notice that something is unpublished; it is not a place to edit. The Settings map explains what each card there is for.

Creating and editing a form needs the form:write privilege — Content Writer and up. Publishing one goes through Deploy, which needs deployment:publish — Content Publisher and up. So a writer can build a form all day and still not be able to make it live; the privilege matrix has the full grid.

The Design tab with the Forms section active in the left panel, showing the search box, sort control, New form button and a list of forms with Contact Us selected

Creating a form

New form asks for one thing: a name. Everything else Leed fills in for you, and every one of those defaults is worth knowing because two of them look like features and are not:

  • Form Prototype is the slugified name — “Contact Us” becomes contact-us.
  • Default Submit Button is Submit.
  • Success Callback is formSubmissionSucceeded and Failure Callback is formSubmissionFailed.
  • Leed Autofill is on.
  • The form has no fields at all. A new form renders as a heading and a button until you add some.

The two callback names are conventions, not implementations. Leed writes them onto the rendered <form> element and calls window["formSubmissionSucceeded"] if such a function exists on your site — and if it does not, nothing happens and nothing breaks. They are hooks waiting for you, not behavior you have been given.

Form settings

The top of Form Details is the whole configuration surface. Every field autosaves as you leave it, and each save raises the toast “Form Saved. Publish to use.” — which is the CMS telling you, every single time, that saving and publishing are two different things.

The Form Details tab of a form scrolled to the top, showing Form Name, Form Prototype, Description, Welcome Back Message, Heading, Details, Default Submit Button, Success Callback, Failure Callback, the Leed Autofill checkbox and the Autofill listbox
SettingStored fieldWhat it doesWhere it shows up on the site
Form NameformNameNames the form in the CMS, in pickers and in the Insert Form dialogNot rendered — but it is the subject line of the internal notification email
Form PrototypeformPrototypeA slug that groups forms sharing one visual designAs a class on the wrapper (<prototype>-container) and on the <form> element (<prototype>)
DescriptiondescriptionInternal note, 400 characters maximumNever — this one is genuinely CMS-only
Welcome Back MessagewelcomeBackMessageGreeting shown to a visitor Leed recognizes; supports {{fieldname}} placeholdersA hidden <div> above the fields, revealed by Leed Autofill when the visitor is known
HeadingheadingHeadline above the formA <div> above the fields, only rendered when set
DetailsdetailsSupporting copy under the headingA second <div> above the fields
Default Submit ButtonbuttonThe submit button’s resting labelThe button’s label — the other five states (Sending …, Email Sent!, Try again!, Thank you!, Downloading …) are fixed
Success CallbacksuccessCallbackNames a global JS function called after a successful submissionA data-successcallback attribute on the <form>; invoked as window[name](formId)
Failure CallbackfailureCallbackNames a global JS function called after a failed submissionA data-failurecallback attribute, invoked the same way
Leed AutofillleedAutofillLets Leed pre-fill or hide fields for a recognized visitorEmits an autofill script call and the welcome-back element
AutofillautofillThird-party autofill provider: None or LinkedInWith LinkedIn, loads LinkedIn’s autofill.js and an IN/Form2 mapping script

Every field you add below these settings is documented option by option in the form field reference — and Leed Autofill deserves particular attention before you turn it off, because it decides how much of the form a returning visitor even sees.

Form prototype

The prototype is a styling hook and nothing else. It is slugified on every write, so typing Landing Page stores landing-page, and it lands on two elements: the container div gets landing-page-container and the <form> itself gets landing-page. The Form Prototype control is a combobox over the prototypes already in use, so picking an existing one is a deliberate act of joining a group.

Success and failure callbacks

Both settings name a global function on your published site — Leed looks up window[name] and, if it finds a function, calls it with the formId as its only argument. If it finds nothing, the submission is unaffected.

The success callback runs after a 200. The failure callback runs on a failed challenge response and on any other non-2xx answer from the capture endpoint. Two cases deliberately run neither: a submission on a preview site, where the endpoint answers 204, shows the “Thank you!” state and returns before either callback is considered. If you are testing a callback and nothing fires, check which site you are on — preview and live behave differently here.

Notification settings

The Notification Settings block is subtitled “Overridable when implemented on pages associated with a campaign.” Read that as: what you set here is the form’s default, and a campaign can override it per page.

The Notification Settings block, showing the campaign-override subtitle, a selected Email Template, a selected Asset and two internal notification email chips

External Notifications email the person who filled the form. You choose an Email Template — one of your email layouts — and optionally an Asset, a document from your library delivered with it. That pairing is how you gate content, and its rules are sharp enough to need their own page: a recognized visitor gets the file immediately rather than by email, and the email itself is sent to any given contact once per form and never again.

Internal Notifications email your team. It is a plain list of email addresses — type one and press Enter, or use Save; each is validated as an email address and a bad one shows Not a valid email rather than being accepted. Added addresses appear as chips you can remove individually. The mail they receive comes from forms-noreply@leed.ai under the name “Leed Forms”, with the subject Leed (<site title>) - Form Submission - <form name>, a table of the submitted values, and a button linking back to /forms/<formId>/submissions in the CMS — which is the Submissions tab, the same view you would open by hand.

Because the subject line carries the form name, distinct names across your forms are worth the trouble: they are what makes an inbox rule possible.

Publishing a form

Editing a form marks it dirty. The form canvas header then shows an amber Unpublished changes chip next to the form’s name; clicking it takes you to Deploy.

flowchart LR
    A["Edit a setting or field"] --> B["Autosave — form marked dirty"]
    B --> C["Deploy shows a pending item<br/>Form: &lt;name&gt;"]
    C --> D["Deployment with reason Forms<br/>targets the live branch"]
    D --> E["Definition merged into<br/>src/_data/leedForms.json"]
    E --> F["Next site build renders it"]
    F --> G["Live on your site"]

In Deploy the pending item reads Form: <name>, the deployment’s reason badge reads Forms, and it targets the live branch. Publishing writes only the forms you selected into src/_data/leedForms.json, merged one entry per formId, and clears their dirty flag — other people’s unpublished form edits stay unpublished. Publishing changes covers the deployment flow itself, and deployment history and status is where you confirm the build finished.

There is no per-form publish button anywhere in the CMS, and no way to publish a form over MCP. An AI client can create and update forms for you, but a person has to publish them through Deploy.

For a form you intend to place in a template you maintain, the Form Details tab offers a copyable snippet just below the Autofill controls:

{{> leed/form formId="a1b2c3d4" }}

That pastes into any template. The form partial documents everything it accepts and emits, and placing a form on a page compares this against the two ways that need no template work at all.

When Leed will not delete a form

The Delete Form button sits at the bottom of Form Details, and it refuses in three distinct ways.

ConditionResponseWhat the CMS showsHow to clear it
Protected system form403 form_protectedButton disabled, with Protected — this form cannot be removed.You cannot; these are owned by a Leed service
Referenced by a page’s Form setting409 form_in_useButton disabled, with Used in N pages — remove from pages first.Clear the Form setting on each of those pages
Has one or more submissions409 form_has_responsesNothing up front — the button is enabled, the dialog offers Delete, and the request fails with an error toastNo self-serve fix today
The bottom of Form Details for a form used by at least one page, showing the disabled Delete Form button and the "Used in N pages — remove from pages first." helper line

What “used by a page” actually counts

The in-use check looks at exactly one thing: the page’s Form setting, on either its latest or its published revision. Nothing else counts.

That means a form embedded in page body content with the editor’s Form block, and a form called from a template with {{> leed/form formId="…" }}, are both invisible to this check. Deleting such a form succeeds — and then the template renders nothing where the form used to be. Before you delete, search your templates as well as trusting the counter.

Deleted and protected forms

A deleted form is hidden, not gone. It disappears from the forms list and from every picker, but its URL still works, and opening it shows a red banner: “This form has been deleted. It’s hidden from the forms list and pickers. Submissions are still queryable. Contact an admin if you need to restore it.” Its submissions remain readable. There is no restore button in the CMS — restoring is an API-only operation (POST /api/forms/:formId/restore), which is what that last sentence in the banner is pointing you at.

Once a form is live and taking submissions, the interesting question stops being how it is built and starts being who is filling it in — that is the Submissions tab and, one step further out, the lead profile each submission attaches itself to.

ESC