Refreshing AJAX Forms in Drupal 7
The Ajax callback should only return the named FAPI element that is to be replaced. For example:

function questionaire_4D_selector_form_ajax_callback($form, $form_state) {
  // If the form has errors we show them in the Preview spot. There's not much
  // else we can do because jQuery is replacing out the specified
  // target element in the #ajax FAPI element.
  if (form_get_errors()) {
    return $form['preview-content-area']['esci-questionaire'];
  }
  return $form['preview-content-area']['esci-questionaire'];
}


Your form_builder function which build/rebuilds the form should examine the $form_state and alter the form as necessary based on the ajax submitted values:

/** Our form builder function */
function questionaire_4d_selector_form($form, &amp;$form_state) {
 # for ajax inspection goto /tmp and view file output.
 #dd($form_state);
 #dpm($form_state);

  // This form responds to an AJAX submit button, and also a $_GET argument.
  $form_passed_get_parameter_questionaire_id = $form_state['submitted'] == FALSE &amp;&amp;
          count($form_state['build_info']['args']) &amp;&amp;
          ctype_digit($form_state['build_info']['args'][0]);
  #dpm($form_passed_get_parameter_questionaire_id ? 1 : 0);
  if ($form_passed_get_parameter_questionaire_id) {
    $id = $form_state['build_info']['args'][0];
  } else {
    $id = !empty($form_state['values']['questionaire_id']) ? $form_state['values']['questionaire_id'] : '';
  }
  #dpm($id);
  $form['questionaire_selector'] = array(
    '#type' =&gt; 'fieldset',
    '#title' =&gt; t('Select 4D Questionaire'),
  );
  $form['questionaire_selector']['access_id'] = array(
    '#type' =&gt; 'hidden',
    '#value' =&gt; drupal_get_token(QUESTIONAIRE_4D_PREVIEW_AJAX_SECRET_VALUE),
  );
  $form['questionaire_selector']['questionaire_id'] = array(
    '#type' =&gt; 'textfield',
    '#title' =&gt; t('Questionaire Number'),
    '#default_value' =&gt; $id,
    '#element_validate' =&gt; array('element_validate_integer_positive'),
    '#size' =&gt; 15,
  );
  $form['questionaire_selector']['submit'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Preview 4D Questionaire'),
    '#ajax' =&gt; array(
      'callback' =&gt; 'questionaire_4d_selector_form_ajax_callback',
      'wrapper' =&gt; 'questionaire-preview',
      'method' =&gt; 'replace',
    ),
  );
  $form['preview-content-area'] = array(
    '#type' =&gt; 'fieldset',
  );
  $form['preview-content-area']['esci-questionaire'] = array(
    '#prefix' =&gt; '&lt;div id="questionaire-preview"&gt;',
    '#suffix' =&gt; '&lt;/div&gt;',
    '#type' =&gt; 'markup',
    '#markup' =&gt; '&lt;h3&gt;Your Questionaire Preview will appear here.&lt;/h3&gt;',
  );

  // This says if we were given an remote 4D form id of say 23456, load it into the supplied FAPI
  // element.
  if ($form_passed_get_parameter_questionaire_id) {
    $remote_response = retrieve_questionaire_4d_response($id);
    if (strpos($remote_response-&gt;data, 'Error',0) === 0) {
      form_set_error('questionaire_selector', "&lt;b&gt;Remote 4D Error&lt;/b&gt;&lt;br&gt;" . $remote_response-&gt;data);
    }
    $form['preview-content-area']['esci-questionaire']['#markup'] = questionaire_4d_selector_build_esci_questionaire_preview($id, $remote_response-&gt;data);
  }

  $form['#attached']['css'] = array(
    drupal_get_path('module', 'questionaire_4d_preview') . '/assets/questionaire_4d_preview.css',
  );
  return $form;
}

/* Implements hook_menu() */
function questionaire_4d_preview_menu() {
  $items['admin/config/esci-online/questionaire-4d-preview'] = array(
    'title' =&gt; '4D Questionaire Preview',
    'description' =&gt; 'View a preview of a remote 4D questionare.',
    'page callback' =&gt; 'drupal_get_form',
    // I'm not sure we have to, but explicitly pass in the 4th
    // argument on the URL as the questionairre ID. This is added
    // to build_info of form automatically.
    'page arguments' =&gt; array('questionaire_4d_selector_form', 4),
    'type' =&gt; MENU_CALLBACK,
    'access arguments' =&gt; array('administer esci'),
  );
  return $items;
}