Skip to content

HTML Library

The HTML library (sf.iife.js, currently 2.7.0) turns any form you already have into a SnipForm form. You keep your markup and CSS; directives on your elements describe what should happen on error, on submit and on success.

  1. Sign in and create a form. Copy its form key.

  2. Wrap your form:

    <snip-form key="YOUR_FORM_KEY">
    <form>
    <input type="email" name="email" sf-validate:required sf-validate:email />
    <div if-error="email" then-show-text></div>
    <button type="submit">Subscribe</button>
    </form>
    <sf-success style="display:none">
    <h2>Thanks for subscribing!</h2>
    </sf-success>
    </snip-form>
  3. Add the script before the closing body tag:

    <script src="https://cdn.snipform.io/api/v2/sf.iife.js" defer></script>
    </body>

Open the page. The form sits idle until a visitor interacts with it, then opens a session with SnipForm and is ready to submit. Submissions appear in the dashboard and on the visitor’s session in Signals.

The host element carries the configuration. Its attributes are read once and removed from the DOM.

AttributeValuePurpose
key or data-keyform keyIdentifies the form. Use data-key if your templating engine strips unknown attributes.
modetestSwaps the real submit for a notice and opens the test panel. Remove before going live.
transitionmilliseconds, none or falseFade duration when directives show or hide elements. Default 150. none disables the fade. The first host on the page sets this for all of them.

Put a form inside the host. If you leave it out, the library creates one, copies the host’s remaining attributes onto it, and moves the host’s content inside.

The library owns submission: it sets action to https://snipform.io, removes method, and intercepts the submit event. A native POST never happens while the script is running. Do not rely on action for a fallback.

Every input, select and textarea with a name is a field. The type is read from the element:

MarkupField typeValue sent
inputits type attribute (text, email, tel, number, date, hidden, …)string
textareatextareastring
selectselectthe selected value
select multipleselect-multiplearray of selected values
several input type="checkbox" sharing a namecheckboxarray of checked values
several input type="radio" sharing a nameradiothe checked value

Two rules:

  • Every field needs a name. A field without one stops the form from loading with [Config error] One or more of your fields do not have a name attribute.
  • Declare every field before the visitor interacts. The field set is frozen when the session opens. A field added to the DOM afterwards is rejected on submit as a data discrepancy. See how forms work.

File inputs are not supported. The server does not accept uploads.

sf-success holds the content shown after a successful submit. Its style="display:none" is removed when it is shown; the content is captured at load and cleared from the DOM until then. Use %fieldname% to print submitted values, and sf-success-script for scripts that should run on success. The V1 sf-result element is still honoured as a fallback. Details in Success content.

If you provide no sf-success, the form’s thank-you content from the dashboard is shown instead.

Directives are plain attributes on your own elements. They never add classes or styles you did not ask for.

GroupDirectivesPage
Validationsf-validate:rule and sf-validate:rule[param], value is the error messageValidation
Error statesif-error, then-show, then-show-text, then-hide, then-class, then-text, then-style; shortcuts error-class, error-style on the input itselfError states
Valid stateselse-class, else-text, else-style, else-hide; shortcuts valid-class, valid-styleValid states
Submit stateson-submit-show, on-submit-hide, on-submit-class, on-submit-text, on-submit-styleSubmit states

if-error without a field name, and the error-* / valid-* shortcuts, infer the field from the element’s own name. Error state directives apply after the first submit attempt and clear field by field as the visitor fixes them.

  1. Scan. On load the library finds every snip-form, reads fields and directives, and tags elements with an sf-node reference.
  2. Human gate. Nothing is sent until the form scrolls into view, or receives focus, a click, a keypress or a touch. That first interaction opens the session.
  3. Session. The field names, types and rules are sent to SnipForm, which checks the key, the domain and the rules, and returns a single-use token plus a honeypot field that the library injects hidden into the form.
  4. Submit. Values and behavioural signals go to SnipForm. Validation errors come back per field and the session stays open. Success swaps the form for the success content.

If the session cannot be opened, the form is replaced by a red SnipForm Error banner that names the cause. The causes are listed under how forms work. The usual ones during setup are a wrong key, a domain that is not the property’s domain, an unpublished form, and a misspelt rule name.

A submit after the 10-minute session window gets a fresh session automatically; the visitor submits again.

Unless your plan removes it, a small “Secured by snipform.io” link is rendered under the form after the session opens. Its text and link come from the server.

The library patches history.pushState and replaceState and listens for popstate, hashchange, and Astro’s astro:before-swap and astro:page-load. After a URL change it disposes forms that left the document and initialises new ones. An anchor scroll on the same page leaves a live form untouched.

The scan runs on load and after URL changes only. A form injected later without a URL change is not picked up, so render forms before the script runs, or load the script after the form exists. If React renders your form, use @snipform/react instead; the DOM mutations this library depends on do not survive a React render.

URLBehaviour
https://cdn.snipform.io/api/v2/sf.iife.jsRolling latest 2.x. Cached for an hour.
https://cdn.snipform.io/api/v2/sf.iife.v2.7.0.jsPinned. Immutable.

Pin in production if you review every dependency change; use the rolling URL if you want fixes without a deploy. Both are safe to load with defer.

A form only loads from its property’s domain. To develop on localhost or 127.0.0.1, switch on Localhost in the form’s settings. Local hits are recorded separately and do not count as views. See Testing for the test panel and workflow.