How can I add custom client-side validation to a Webform field using advanced custom properties? The setup:

I have a Drupal 8 form created manually, and I would like to recreate it using Webform module.

So far, I have managed to recreate everything (required fields and submission handler), but there is a last bit missing: the client-side validation that triggers on change.

The initial form have fields defined as follows:

$form['first-name'] = array(
  '#type' =&gt; 'textfield',
  '#title' =&gt; $this-&gt;t('First name'),
  '#required' =&gt; true,
  '#required_error' =&gt; $this-&gt;t('This is a required field. Please enter your first name.'),
  '#ajax' =&gt; [
    'callback' =&gt; '::validateFnameAjax',
    'effect' =&gt; 'fade',
    'event' =&gt; 'change',
    'progress' =&gt; FALSE,
  ],
);


Calling validation functions like this one:

public function validateFnameAjax(array &amp;$form, FormStateInterface $form_state) {
  $response = new AjaxResponse();
  $errorValidation = '&lt;div class="form-item-message form-item__error-message"&gt;&lt;small class="text-danger"&gt;&lt;/small&gt;&lt;/div&gt;';
  $successValidation = '&lt;div class="form-item-message form-item__success-message"&gt;&lt;small class="text-success"&gt;&lt;/small&gt;&lt;/div&gt;';
  // Assert the name field has been included
  if (!$form_state-&gt;getValue('first-name') || empty($form_state-&gt;getValue('first-name'))) {
    $message = $this-&gt;t('This is a required field. Please enter your first name.');
    $response-&gt;addCommand(new InvokeCommand('.staff-register-form .js-form-item-first-name .form-text', 'removeClass', ['is-valid']));
    $response-&gt;addCommand(new InvokeCommand('.staff-register-form .js-form-item-first-name .form-text', 'addClass', ['is-invalid']));
    $response-&gt;addCommand(new ReplaceCommand('.js-form-item-first-name .form-item-message', $errorValidation));
    $response-&gt;addCommand(new HtmlCommand('.js-form-item-first-name .text-danger', $message));
  }
  else {
    $message = $this-&gt;t('Your first name is valid.');
    $response-&gt;addCommand(new InvokeCommand('.staff-register-form .js-form-item-first-name .form-text', 'removeClass', ['is-invalid']));
    $response-&gt;addCommand(new InvokeCommand('.staff-register-form .js-form-item-first-name .form-text', 'addClass', ['is-valid']));
    $response-&gt;addCommand(new ReplaceCommand('.js-form-item-first-name .form-item-message', $successValidation));
    $response-&gt;addCommand(new HtmlCommand('.js-form-item-first-name .text-success', $message));
  }
  return $response;
}


In the new webform function I have changed lines one and six, but the rest of the code is the same.

New line one:

  public function validateFnameAjax(WebformSubmissionInterface $webform_submission) {


New line 6:

  if (!$webform_submission-&gt;getElementData('first_name') || empty($webform_submission-&gt;getElementData('first_name'))) {


The challenge:

Implement the same behaviour: trigger the custom validation when the content in the field changes (before submission).

Current status:

I have tried to include the Ajax properties using the Advanced tab of the edit field UI as you can see in the following screenshots:





But I get this error in the log:


  Symfony\Component\HttpKernel\Exception\HttpException: The specified #ajax callback is empty or not callable. in Drupal\Core\Form\FormAjaxResponseBuilder->buildResponse() (line 67 of /var/www/drupalvm/web/core/lib/Drupal/Core/Form/FormAjaxResponseBuilder.php).


Does anyone know what am I doing wrong to get this error, and how to make this client side validation work?
Although this answer does not provide the solution to add custom client-side validation to a Webform field using advanced custom properties, it provides a working alternative to add client-side validation to a Webform field. 

Given that Webform UI comes with the option to add custom CSS and Javascript to a Webform, I have made use of this option to add my custom validation.