Add form field with AJAX Here is the form:

function payment_form($form, &amp;$form_state) {
  $form['#tree'] = TRUE;

  // since credit card is also an option, the gift card section is contained in this div.
  $form['payment']['giftcard'] = array(
    '#type' =&gt; 'container',
  );

  // there are additional fields above here, but trimmed them out since they are not relevant to the issue.
  $form['payment']['giftcard']['giftcards'] = array(
    '#type' =&gt; 'container',
    '#attributes' =&gt; array(
      'class' =&gt; array('giftcards'),
    ),
    '#prefix' =&gt; '&lt;div class="giftcards-wrapper"&gt;',
    '#suffix' =&gt; '&lt;/div&gt;',
  );

  // initialize the gift card field counter
  if (!isset($form_state['gift_cards'])) {
    $form_state['gift_cards'] = 1;
  }
  // build the fields
  for ($i = 0; $i &lt; $form_state['gift_cards']; $i++) {
    $form['payment']['giftcard']['giftcards']['gift_card_number'][$i] = array(
      '#type' =&gt; 'textfield',
      '#title' =&gt; t('Gift Card Number'),
      '#title_display' =&gt; 'invisible',
    );
  }
  // validate the current gift card and add another field.
  $form['payment']['giftcard']['giftcards']['validate'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Validate'),
    '#ajax' =&gt; array(
      'callback' =&gt; 'validate_giftcard_add_field',
      'wrapper' =&gt; 'giftcards-wrapper',
      'method' =&gt; 'replace',
    ),
  );


Here is the callback function for the AJAX call. There is no validation currently, just trying to get it to add another field. If I add print statements in this function they are being output in a javascript alert, so this function is being called. However it is not returning any new fields.

function validate_giftcard_add_field($form, $form_state) {
  $form_state['gift_cards']++;

  return $form['payment']['giftcard']['giftcards'];
}


What is the right way to add new fields via ajax?

Additionally, all instances of  '#required' =&gt; TRUE, have been removed during my testing. I have not done anything with the validate or submit callbacks either.
#ajax-&gt;wrapper refers to an ID. Where as you have class="giftcards-wrapper". Change it to ID and it should replace it.