Front-end JS#

The default Form Template used by Formie uses custom JS when rendering the form. This is to provide out-of-the-box functionality for forms, so you don't need to worry about things like validation, multi-page setup and Ajax submissions.

The default JavaScript is split into two files, and can be disabled in your Form Templates should you wish to implement your own JavaScript for functionality. Both files are bundled in a single JS file. The gzipped size of this file is roughly 20kb, and comes with all required polyfills to support 90% browser coverage (opens new window).

It is also loaded using defer to ensure loading doesn't block the page render.

Form Base#

This JavaScript is minimal, providing event hooks for the form and fields, along with easy translation handling for strings. It also provides these event hooks so that Captchas like ReCAPTCHA can work correctly.

Form Theme#

This JavaScript is a little more opinionated, and provides the following:

  • Translatable client-side validation (via Bouncer.js (opens new window))
  • Multi-page handling
  • Success/error message handling
  • Ajax submissions
  • Loading indicator
  • Disabling the submit button when clicked
  • Prompting the user they have unsaved changes, if trying to navigate away

Field-specific JS#

Some fields also require additional JS to be rendered alongside the field. Fortunately, these are lazy-loaded only if the field is actually used in the form. These are:


This helper provides toggling of aria-checked and aria-required attributes for checkboxes and radios. In addition, there is currently no native HTML5 validation behaviour for validating a group of checkbox fields. This is if you want the user to select at least one option in a collection of checkboxes. This helper also provides this functionality.

File Upload#

This helper is provided to assist with limits set on the field, by the types of files allowed to upload and the file-size limit.


This helper provides functionality to the Repeater field, namely by handling adding or removing new rows of repeatable content.


This helper provides functionality to the Table field, namely by handling adding or removing new rows of repeatable content.


This helper provides functionality to create tags for a Tag field. It uses Tagify (opens new window).


For Single-line Text and Multi-line text fields, and if the Limit options are set, this will display a counter for either characters or words to limit the text for these fields. It will also prevent typing past these limits.

Form Templates#

Your Form Templates can control where and how the JS for a form is rendered. You can also disable the "Form Base" or "Form Theme" JavaScript, if you wish to write your own JS.

Be aware that if disabling the "Form Base" you will lose Formie's submit-handler binding on the form. This will mean reCAPTCHA will not work on your forms, as it relies on interrupting the submission of a form to validate. You will need to manage reCAPTCHA yourself.

For example, if you wish to disable the "Form Theme", client-side validation will no longer work. It will be up to you to implement this behaviour for your site.

Render Location#

By default, Formie will render a single formie.js right before the </body> tag at the end of the page. You can choose to either render it Inside Form, or Manual - Manual essentially disabling rendering.

Manual Render#

You can select exactly where you'd like the JavaScript for forms to be output on the page, using craft.formie.renderFormJs()

<div class="form-wrap">
    {{ craft.formie.renderForm('myForm') }}

{{ craft.formie.renderFormJs('myForm') }}

You could also use a Form object instead of the handle.

{% set form = craft.formie.forms({ handle: 'myForm' }).one() %}

<div class="form-wrap">
    {{ craft.formie.renderForm(form) }}

{{ craft.formie.renderFormJs(form) }}

Here, we have split the rendering of the form to the HTML for the form, then the JS for the form. This can be particularly useful for Vue.js, where <script> elements generated by Formie shouldn't be included within a template - or if your page doesn't have a </body> to attach it to.

There are also further scenarios where you want more fine-grained control over the JavaScript, which we'll explore in JavaScript API.

Submit with JavaScript (Ajax)#

You can also trigger form submission through JavaScript.

let $form = document.querySelector('#formie-form-1');
let data = new FormData($form);

fetch('/', {
    method: 'post',
    body: data,
    headers: {
        'Accept': 'application/json',
        'X-Requested-With': 'XMLHttpRequest',
}).then(function(response) {
    response.json().then(function(data) {
let data = $('#formie-form-1').serialize();

    type: 'POST',
    url: '/',
    data: data,
    cache: false,
    dataType: 'json',
    error: function(jqXHR, textStatus, errorThrown) {
    success: function(response) {

If you're unable to use FormData or serialize(), or you're constructing the payload for the action yourself, you'll need to provide the CSRF token and the action to perform in your payload.

<script type="text/javascript">
    window.csrfTokenName = "{{|e('js') }}";
    window.csrfTokenValue = "{{|e('js') }}";
let data = {
    action: 'formie/submissions/submit',
    handle: 'contactForm',
    siteId: 1,
    fields: {
        yourName: 'Peter Sherman',
        emailAddress: '[email protected]',
        message: 'Hello there!',

// Add the CSRF Token
data[csrfTokenName] = csrfTokenValue;

Previous ← Front-end CSS Next JavaScript API →