How to AJAX form with recaptcha?


My forms were working fine with AJAX based on this document:

But since some recent updates, the AJAX part ceased to work. Now after submission of the form, the whole page is reloaded and the response message appears alone on this empty page.

When I disable the captcha, things work fine.

After some testing:
It works with Grav v1.6.19 and Form v3.0.8.
But fails when I update to Form v4.0.0.

Any news about this bug?

@ontime, If you want to notify the developers of some malfunction in the forms plugin, you should submit an issue at

The community cannot do much in these cases…

@ontime have you found a solution for this?

@cchinopoulos, Did you visit the repo of grav-plugin-form as mentioned above?

I use reCaptcha v2 (checkbox) on my page with Form plugin v6.0.0 and it works just fine with Ajax form :thinking: I remember it took a while to implement Ajax form in the module page overall, but there’s no issue now

1 Like

@Karmalakas, Sounds great! Would you mind sharing your code and also update the issue on Github?

I don’t think I have anything special there. Just handling of submit to re-render the response :thinking:

Frontamatter of the form page (a bit stripped down):

visible: false
debugger: false
    ignore: true
  name: contact-form
  action: '/form'
  client_side_validation: false
  inline_errors: true
  keep_alive: true

      id: contact-name
      name: name
      autocomplete: true
      type: text
        required: true
      id: contact-email
      name: email
      type: email
        required: true
        type: email
      name: g-recaptcha-response
      type: captcha
      label: Captcha

      type: submit

      captcha: true
      reset: true

In modular.html.twig:

{% include "forms/ajax-form-wrapper.html.twig" with {form_page: page.find('/form')} %}


{% do assets.addJs('jquery', 101) %}
{% do assets.addJs('', 50) %}
{% do assets.addJs('theme://js/form.min.js', 25) %}

{% set form_page = form_page ?? page %}
{% set page_form = page_form ?: (forms({"route": form_page.route}) ?: forms('contact-form')) %}

{% if page_form %}
    <div id="form-result-{{ }}" class="text-left">
        {% include "forms/form.html.twig" with {form: page_form} %}
        $(function () {
            bindAjaxFormSubmit('{{ }}', '{{ uri.base ~ uri.uri }}');
{% endif %}


function ajaxReq() {
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        return new ActiveXObject('Microsoft.XMLHTTP');
    } else {
        alert('Browser does not support XMLHTTP.');

        return false;

function bindAjaxFormSubmit(id, page_url) {
    page_url = page_url ||;
    const xhr = ajaxReq();
    const responseHolder = document.getElementById('form-result-' + id);

    document.getElementById(id).addEventListener('submit', function (e) {
        this.querySelector('button[type="submit"]').disabled = true;'method'), this.getAttribute('action'), true);
        xhr.send(new FormData(this));

        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && xhr.status === 200) {
                saferInnerHTML(responseHolder, xhr.response);
                bindAjaxFormSubmit(id, page_url);
    }, false);

Part of form.yaml:

  version: 2-checkbox

Not sure what I should update on GitHub issue :thinking:

1 Like

@Karmalakas, Thanks!

I use reCaptcha v2 (checkbox) on my page with Form plugin v6.0.0 and it works just fine with Ajax form

You make it sound as if adding reCaptcha to the Ajax tutorial mentioned before is a piece of cake and is working fine. However, your code seems quite complex…

Is all of your code needed to get reCaptcha to work instead of merely adding a captcha field and process field?

IIRC, this all code and additional template was needed just to make Ajax work in modular page and has nothing to do with reCaptcha itself. It’s been a couple of years now I think, so my memory might play tricks, but I’m pretty sure this is the case :slight_smile: And with this approach I can now add my Ajax form wherever I want