I'm using the Form API to create a form where I have multiple instances of a fieldset. Each fieldset contains the same fields, one for storing an email address and another for another bit of information. But essentially they're both textfields that use autocomplete which works fine. But I'm having an issue in the submission handler, described underneath my code below.

$form['authors_container']['authors_fieldset'][$i] = [
    '#type' => 'fieldset',
    '#attributes' => [
      'class' => ['author-fieldset']
    'email' => [
      '#type' => 'textfield',
      '#title' => 'Author email',
      '#value' => $emailValue,
      '#autocomplete_route_name' => 'discussion_papers.contact_email_lookup',
      '#attributes' => [
        'class' => ['author-email']
    'affiliation' => [
      '#type' => 'textfield',
      '#title' => 'Affiliation',
      '#value' => $affiliationValue,
      '#attributes' => [
        'class' => ['author-affiliation']

I then have an AJAX button for adding more instances of the above fieldset with its corresponding handler:

$form['authors_container']['add_author'] = [
  '#type' => 'submit',
  '#value' => 'Add another author',
  '#submit' => ['::AddAuthor'],
  '#limit_validation_errors' => [],
  '#ajax' => [
    'callback' => '::getAuthorsFields',
    'wrapper' => 'authors-container',
    'method' => 'replace',
    'disable-refocus' => true,

public function addAuthor($form, FormStateInterface &$form_state) {

    $storage = $form_state->getStorage();

    if (empty($storage['numOfAuthors'])) 
        $storage['numOfAuthors'] = 1;



All this works fine, I can add as many instance of the fieldset as I need. My issue is that when I submit the form, the values of only the very last fieldset are always empty in the $form_state['values'] array, yet I can see the values in the $form_state['input'] array. I understand that the input array is raw, unvalidated input and that the values array is validated, so my question is why are only the last set of textfields not validated? My validation handler doesn't remove any values.

1 Answer 1


Two possibilities:

  1. You have added the additional fields in the #ajax callback function. As you didn't show which function your fields were defined in, this cannot be seen from your code. Drupal caches the form when building it, then when the form is submitted, it will strip any values not part of the original form definition for security purposes. The problem with adding fields in an #ajax callback function is that the form is cached previous to the callback function, and therefore Drupal discards the submitted values of the fields.

  2. If the form element declarations are in fact within the form builder function and not part of an #ajax callback function, you probably need to add #tree to the fieldset, so as to create an array of values:

    $form['authors_container']['authors_fieldset'][$i] = [
      '#tree' => TRUE,
      '#type' => 'fieldset',

    This will save each of the submitted values to a separate element of the values array.

  • Thanks for the reply, I'll try to edit my question to include more code. The additional fields are only added in the buildForm method, the AJAX callback only increases the number that should show and then on the form rebuild, it adds however many are stored in the form state storage. I've tried adding the tree key and also disabling cache but neither helped. The tree key is also used in the container parent of the fieldsets. I think I need to debug right from the beginning of the submission request to find out why Drupal removes them. Feb 10, 2022 at 17:41
  • If you're changing values in the form state in an ajax callback, they are lost. The form state has already been cached prior to the ajax callback. You will need to do your incrementation in a submit handler, not an ajax callback, if you want it to persist. Ajax callbacks are only for determining which elements to return, not for "doing" anything to the data.
    – Jaypan
    Feb 12, 2022 at 1:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.