The curious case of a Drupal Button The code below is used to get the word count of a field (field_body) using ajax callback. It works great and everything functions as it should, well almost.
For some reason, the click of a button is also calling the default node form submit action. 

So what happens is after I update count, and suppose I don't save the content. In fact, just go to another page or refresh the page, I get something like 
Categories is required
Tags is required
Thumbnail is required.... 

Basically whatever I would get on form validation. It's just that the result is delayed as I am using ajax.

The problem is not with ajax, because even I comment the callback, and I click the button it tries to submit the form, when clearly it should not as executes submit callback is False.

function hook_form_alter(&amp;$form, &amp;$form_state, $form_id) {
  if ($form_id == 'article_node_form' || $form_id == 'q_and_a_node_form' ) {

    $form['get_word_count'] = array(
     '#type' =&gt; 'button',
     '#value' =&gt; t('Update Count'),
     '#weight' =&gt; 5,
     '#executes_submit_callback' =&gt; FALSE,
     '#ajax' =&gt; array(
      'callback' =&gt; 'count_words',
      ),
    );

    $form['body_words'] = array(
     '#title' =&gt; t('Words in Body'),
     '#type' =&gt; 'textfield',
     '#disabled' =&gt; TRUE,
     '#weight' =&gt; 5,
     '#prefix' =&gt; '&lt;div id="replace_body_words"&gt;',
     '#suffix' =&gt; '&lt;/div&gt;',
    );
   $form['field_length_type']['#prefix'] = '&lt;div id="replace_field_length_type"&gt;';
    $form['field_length_type']['#suffix'] = '&lt;/div&gt;'; 
  }
}

function count_words($form, $form_state) {
  $str = $form['field_body']['und'][0]['value']['#value'];
  $count = preg_match_all("/\S+/", preg_replace('/(' . chr(160) .'|&amp;nbsp;)/', ' ', strip_tags(str_replace('&gt;&lt;', '&gt; &lt;', trim($str)))), $matches);
  $form['body_words']['#value'] = $count;
  if ($count &lt; 500) {
    $form['field_length_type']['und']['#value'] = "short";
  }
  else if ($count &gt; 500 &amp;&amp; $count &lt; 800 ) {
    $form['field_length_type']['und']['#value'] = "medium";
  }
  else {
    $form['field_length_type']['und']['#value'] = "long";
  }
  return array(
    '#type' =&gt; 'ajax',
    '#commands' =&gt; array(
      ajax_command_replace("#replace_body_words", $form['body_words']),
      ajax_command_replace("#replace_field_length_type", $form['field_length_type'])
     )
   );
 }
}


Any help would be much appreciated. Any workaround?
When using the #type =&gt; 'button' the submit callback is never executed, it already receives  a FALSE as default value.

Even if the submit callback is not executed, the validate callback is always executed (even on ajax posts). You can bypass this validation on a trigger element by using the #limit_validation_errors property.

In your case, you can set it on the body_words form element to only validate on this scope instead of the whole form.

$form['get_word_count'] = array(
    '#type' =&gt; 'button',
    '#value' =&gt; t('Update Count'),
    '#weight' =&gt; 5,
    '#limit_validation_errors' =&gt; array(
        array('body_words'),
    ),
    '#ajax' =&gt; array(
        'callback' =&gt; 'count_words',
    ),
);