How do I add a "Add more" button? I want to  show a Add more button that adds an extra text field and the corresponding Remove button.

I followed ajax_example_add_more() to achieve this in Drupal 7. For Drupal 8, I tried with the following code.

class XmlfeedsSettingsForm extends FormBase {
  public function getFormId() {
    return 'formid';
  }


  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
   // Because we have many fields with the same values, we have to set
  // #tree to be able to access them.
  $form['#tree'] = TRUE;
  $form['names_fieldset'] = array(
    '#type' =&gt; 'fieldset',
    '#title' =&gt; t('People coming to the picnic'),
    // Set up the wrapper so that AJAX will be able to replace the fieldset.
    '#prefix' =&gt; '&lt;div id="names-fieldset-wrapper"&gt;',
    '#suffix' =&gt; '&lt;/div&gt;',
  );

  // Build the fieldset with the proper number of names. We'll use
  // $form_state['num_names'] to determine the number of textfields to build.
  $form_state-&gt;getValue['num_names_parent'] = '';
  if (empty($form_state-&gt;getValue['num_names_parent'])) {
    $form_state-&gt;getValue['num_names_parent'] = 1;
  }
  for ($i = 0; $i &lt; $form_state-&gt;getValue['num_names_parent']; $i++) {
    $form['names_fieldset']['name'][$i] = array(
      '#type' =&gt; 'textfield',
      '#title' =&gt; t('Name'),
    );
  }
  $form['names_fieldset']['add_name'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Add one more'),
    '#submit' =&gt; array('::ajax_example_add_more_add_one'),
    // See the examples in ajax_example.module for more details on the
    // properties of #ajax.
    '#ajax' =&gt; array(
      'callback' =&gt; '::ajax_example_add_more_callback',
      'wrapper' =&gt; 'names-fieldset-wrapper',
    ),
  );
  if ($form_state-&gt;getValue['num_names_parent'] &gt; 1) {
    $form['names_fieldset']['remove_name'] = array(
      '#type' =&gt; 'submit',
      '#value' =&gt; t('Remove one'),
      '#submit' =&gt; array('::ajax_example_add_more_remove_one'),
      '#ajax' =&gt; array(
        'callback' =&gt; '::ajax_example_add_more_callback',
        'wrapper' =&gt; 'names-fieldset-wrapper',
      ),
    );
  }
  $form['submit'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Submit'),
  );

  // This simply allows us to demonstrate no-javascript use without
  // actually turning off javascript in the browser. Removing the #ajax
  // element turns off AJAX behaviors on that element and as a result
  // ajax.js doesn't get loaded.
  // For demonstration only! You don't need this.
 // if ($no_js_use) {
    // Remove the #ajax from the above, so ajax.js won't be loaded.
//    if (!empty($form['names_fieldset']['remove_name']['#ajax'])) {
//      unset($form['names_fieldset']['remove_name']['#ajax']);
//    }
//    unset($form['names_fieldset']['add_name']['#ajax']);
 // }

  return $form;
  }
  public function ajax_example_add_more_add_one(array &amp;$form, FormStateInterface $form_state) {
      print_R($form_state);die;
  //$form_state-&gt;getValue['num_names_parent']++;
  //$form_state-&gt;setRebuild(TRUE);


}
public function ajax_example_add_more_callback(array &amp;$form, FormStateInterface $form_state) {
  return $form['names_fieldset'];

}
public function ajax_example_add_more_remove_one(array &amp;$form, FormStateInterface $form_state) {
  if ($form_state-&gt;getValue['num_names_parent'] &gt; 1) {
    $form_state-&gt;getValue['num_names_parent']--;
  }
  $form_state['rebuild'] = TRUE;
}


print_r($form_state) in buildForm() outputs the following. 

[getValue] =&gt; Array
        (
            [num_names_parent] =&gt; 1
        )


In ajax_example_add_more_add_one(), the num_names_parent index is missing.

How can I correctly add the 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);
  }
}