How do I add a "Add more" button?
It works !! Try this
&lt;?php
  
namespace Drupal\fapi_example\Form;
   
use Drupal\Core\Form\FormStateInterface;
  
class AjaxAddMore extends FormBase {
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['description'] = array(
      '#markup' =&gt; '&lt;div&gt;'. $this-&gt;t('This example shows an add-more and a remove-last button.').'&lt;/div&gt;',
    );

    $i = 0;
    $name_field = $form_state-&gt;get('num_names');
    $form['#tree'] = TRUE;
    $form['names_fieldset'] = [
      '#type' =&gt; 'fieldset',
      '#title' =&gt; $this-&gt;t('People coming to picnic'),
      '#prefix' =&gt; '&lt;div id=&quot;names-fieldset-wrapper&quot;&gt;',
      '#suffix' =&gt; '&lt;/div&gt;',
    ];
    if (empty($name_field)) {
      $name_field = $form_state-&gt;set('num_names', 1);
    }
    for ($i = 0; $i &lt; $name_field; $i++) {
      $form['names_fieldset']['name'][$i] = [
      '#type' =&gt; 'textfield',
      '#title' =&gt; $this-&gt;t('Name'),
      ];
    }
    $form['actions'] = [
      '#type' =&gt; 'actions',
    ];
    $form['names_fieldset']['actions']['add_name'] = [
      '#type' =&gt; 'submit',
      '#value' =&gt; $this-&gt;t('Add one more'),
      '#submit' =&gt; array('::addOne'),
      '#ajax' =&gt; [
      'callback' =&gt; '::addmoreCallback',
      'wrapper' =&gt; 'names-fieldset-wrapper',
      ],
    ];
    if ($name_field &gt; 1) {
      $form['names_fieldset']['actions']['remove_name'] = [
      '#type' =&gt; 'submit',
      '#value' =&gt; $this-&gt;t('Remove one'),
      '#submit' =&gt; array('::removeCallback'),
       '#ajax' =&gt; [
        'callback' =&gt; '::addmoreCallback',
        'wrapper' =&gt; 'names-fieldset-wrapper',
      ]
      ];
    }
    $form_state-&gt;setCached(FALSE);
    $form['actions']['submit'] = [
      '#type' =&gt; 'submit',
      '#value' =&gt; $this-&gt;t('Submit'),
    ];
  
    return $form;
  }
  
  public function getFormId() {
    return 'fapi_example_ajax_addmore';
  }

  public function addOne(array &amp;$form, FormStateInterface $form_state) {
    $name_field = $form_state-&gt;get('num_names');
    $add_button = $name_field + 1;
    $form_state-&gt;set('num_names', $add_button);
    $form_state-&gt;setRebuild();
  }

  public function addmoreCallback(array &amp;$form, FormStateInterface $form_state) {
    $name_field = $form_state-&gt;get('num_names');
    return $form['names_fieldset'];
  }

  public function removeCallback(array &amp;$form, FormStateInterface $form_state) {
    $name_field = $form_state-&gt;get('num_names');
    if ($name_field &gt; 1) {
      $remove_button = $name_field - 1;
      $form_state-&gt;set('num_names', $remove_button);
    }
    $form_state-&gt;setRebuild();
  }
  
  public function submitForm(array &amp;$form, FormStateInterface $form_state) {
    $values = $form_state-&gt;getValue(array('names_fieldset', 'name'));
  
    $output = t('These people are coming to the picnic: @names', array(
      '@names' =&gt; implode(', ', $values),
      )
    );
    drupal_set_message($output);
  }
}