Freeform Javascript Plugin

If you wish to extend the capabilities of Freeform's front-end Javascript plugin, please refer to the documentation below:

Getting the Plugin Instance

Let's assume you have a form tag with an ID in your HTML like so:

<form id="my-form">
   ...
</form>
1
2
3

You can get the plugin instance in two ways, whichever is more convenient to you:

Once you have the form element, you can either use the static ::getInstance() method on the Freeform plugin class, like so:

const form = document.getElementById("my-form");
const freeform = Freeform.getInstance(form);
1
2

Or you can access the Freeform JS Plugin instance via the element's freeform property, like so:

const form = document.getElementById("my-form");
const freeform = form.freeform;
1
2

To hook into the Freeform JS plugin once the plugin has been initialised your form element has to be listening to the freeform-ready event:

const form = document.getElementById("my-form");
form.addEventListener("freeform-ready", function (event) {
    const freeform = event.target.freeform;
    // your custom code here
})
1
2
3
4
5

When to Call your Custom Scripts

When setting form scripts to be loaded inside forms, the Freeform JS plugin instance will be accessible to scripts that are called inside the footer. Load your custom script in the footer and call the Freeform JS plugin instance directly from the form object, like so:

  const form = document.getElementById("my-form");
  form.freeform.setOption("successBannerMessage", "This is a custom success message");
1
2

If you have set the form scripts to be loaded inside the footer, then it's best to attach an event listener to the form object which will execute once the Freeform JS plugin instance has finished initializing. Use this script before the rest of the footer scripts, but after the form has been rendered, like so:

  const form = document.getElementById("my-form");
  form.addEventListener("freeform-ready", function (event) {
    event.target.freeform.setOption("successBannerMessage", "This is a custom success message");
  });
1
2
3
4

Adding callbacks

Once you have the plugin instance, you can attach callbacks to it to perform the things you intend to perform:

On Submit callback

To perform something when the form is being submitted and decide whether it should finish submitting or stop, use ::addOnSubmitCallback(callback) method. It lets you add a callback function to the stack of callback functions which will run before the form is submitted. Returning false in the callback, will prevent the form from being submitted. The callback function receives two arguments - the form element and the freeform plugin's options.

const form = document.getElementById('#my-form');
form.addEventListener('freeform-ready', function(event) {
  const freeform = event.target.freeform;
  freeform.addOnSubmitCallback((formElement, options) => {
    return formElement.dataset.myDataItem !== 'not-what-im-looking-for';
  });
});
1
2
3
4
5
6
7

AJAX callbacks

If the form has AJAX enabled, a couple more callbacks can be added to the form.

const form = document.getElementById('my-form');
form.addEventListener('freeform-ready', function(event) {
  const freeform = event.target.freeform;
  freeform.addOnSuccessfulAjaxSubmit((event, form, response) => {
    // Do something on a successful ajax submit
  })
});
1
2
3
4
5
6
7
const form = document.getElementById('my-form');
form.addEventListener('freeform-ready', function(event) {
  const freeform = event.target.freeform;
  freeform.addOnFailedAjaxSubmit((event, form, response) => {
    // Do something on a failed ajax submit
  })
});
1
2
3
4
5
6
7
const form = document.getElementById('my-form');
form.addEventListener('freeform-ready', function(event) {
  const freeform = event.target.freeform;
  freeform.addOnAfterAjaxSubmit((event, form, response) => {
    // Do something after every ajax submit is completed, regardless of it being successful or not
  })
});
1
2
3
4
5
6
7

Plugin Options

The Freeform JS Plugin has several options that let you override the way it works. Mainly, the options are for rendering AJAX form success or failure messages.

You can override the options by using the ::setOption(name, value) method:

const form = document.getElementById('my-form');
form.addEventListener('freeform-ready', function(event) {
  const freeform = event.target.freeform;

  // Enable AJAX. This happens automatically if you enable AJAX via the form composer
  freeform.setOption('ajax', true);

  // Attach a custom function that handles message removal, if you need custom logic.
  freeform.setOption('removeMessages', function() {
    // This is bound to the Freeform instance
    this.form.querySelectorAll('.ff-errors').remove();
    this.form.querySelectorAll('.ff-form-success').remove();
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14

The available options are:

  • successBannerMessage - a string containing the success message you want to see if the AJAX form has been successfully posted.
  • errorBannerMessage - a string containing the error message you want to see if the AJAX form has failed.
  • errorClassBanner - a string containing the class name of the banner that contains form error messages.
  • errorClassList - a string containing the class name of the error message list element under invalid fields.
  • errorClassField - a string containing the class name of input elements that contain errors.
  • successClassBanner - a string containing the class name of the banner that contains the success message.
  • removeMessages - a function that handles removing all error and success messages from a form.
  • renderSuccess - a function that creates and displays the success banner.
  • renderFormErrors - a function that creates and displays the form error message banner. Receives messages as the first argument.
  • renderFieldErrors - a function that creates and displays the field error messages. Receives messages as the first argument.

Examples:

const form = document.getElementById('my-form');
form.addEventListener('freeform-ready', function(event) {
  const freeform = event.target.freeform;

  freeform.setOption('successBannerMessage', 'My custom success message');
  freeform.setOption('errorBannerMessage', 'My custom error message');

  freeform.setOption('errorClassBanner', 'my-custom-error-banner');
  freeform.setOption('errorClassList', 'my-custom-errors-list');
  freeform.setOption('errorClassField', 'this-field-has-errors');
  freeform.setOption('successClassBanner', 'my-custom-success-banner');

  freeform.setOption('removeMessages', function() {
    this.form.querySelectorAll('.my-custom-error-banner').remove();
    this.form.querySelectorAll('.my-custom-success-banner').remove();
    this.form.querySelectorAll('.my-custom-errors-list').remove();
  });

  freeform.setOption('renderSuccess', function() {
    const successMessage = document.createElement("div");
    successMessage.classList.add("my-custom-success-banner");
    successMessage.appendChild(document.createTextNode("Form submitted successfully"));

    this.form.insertBefore(successMessage, this.form.childNodes[0]);
  });

  freeform.setOption('renderFormErrors', function(errors) {
    const errorBlock = document.createElement("div");
    errorBlock.classList.add("my-custom-errors-banner");

    const paragraph = document.createElement("p");
    paragraph.appendChild(document.createTextNode("Form contains errors!"));
    errorBlock.appendChild(paragraph);

    if (errors.length) {
      const errorsList = document.createElement("ul");
      for (let messageIndex = 0; messageIndex < errors.length; messageIndex++) {
        const message = errors[messageIndex];
        const listItem = document.createElement("li");

        listItem.appendChild(document.createTextNode(message));
        errorsList.appendChild(listItem);
      }

      errorBlock.appendChild(errorsList);
    }

    this.form.insertBefore(errorBlock, this.form.childNodes[0]);
  });

  freeform.setOption('renderFieldErrors', function(errors) {
    for (const key in errors) {
      if (!errors.hasOwnProperty(key) || !key) {
        continue;
      }

      const messages = errors[key];
      const errorsList = document.createElement("ul");
      errorsList.classList.add("my-custom-errors-list");

      for (let messageIndex = 0; messageIndex < messages.length; messageIndex++) {
        const message = messages[messageIndex];
        const listItem = document.createElement("li");
        listItem.appendChild(document.createTextNode(message));
        errorsList.appendChild(listItem);
      }

      const inputList = this.form.querySelectorAll("*[name=" + key + "], *[name='" + key + "[]']");
      for (let inputIndex = 0; inputIndex < inputList.length; inputIndex++) {
        const input = inputList[inputIndex];
        input.classList.add("this-field-has-errors");
        input.parentElement.appendChild(errorsList);
      }
    }
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
Last Updated: 7/8/2019, 10:48:39 PM