Attach #ajax to submit button created in hook_form_alter with #markup I created a custom submit button for the user-login form using #markup because I couldn't alter submit button html to resemble what I needed. The second custom submit button with the needed html is added with:

$form['submit2'] = array(
  '#markup' =&gt; '&lt;p class="submit"&gt;&lt;button type="submit" name="submit"&gt;&lt;i class="icon-arrow-right icon-large"&gt;&lt;/i&gt;&lt;/button&gt;&lt;/p&gt;');


I then added a "hideme" class to the orginal button with $form['actions']['submit'] ['#attributes'] (deleting it stopped the other submit from working).

So far so good. But now I would like to validate the login form using AJAX. Only if I add the #ajax key to $form['submit2'], the callback is never called. This only seems to work with regular form items.

Is it possible to trigger an Ajax callback on a #markup element (in hook_form_alter)? I'm using Drupal 7.
You cannot, since the #ajax attribute is not used for the markup item. You can use an image_button form element.

If the image_button form element doesn't render as you want and it is not possible to alter it the way you want, you need to implement a new form element with hook_element_info(), using the definition of the image_button form element as guide.

  $types['image_button'] = array(
    '#input' =&gt; TRUE,
    '#button_type' =&gt; 'submit',
    '#executes_submit_callback' =&gt; TRUE,
    '#limit_validation_errors' =&gt; FALSE,
    '#process' =&gt; array('ajax_process_form'),
    '#return_value' =&gt; TRUE,
    '#has_garbage_value' =&gt; TRUE,
    '#src' =&gt; NULL,
    '#theme_wrappers' =&gt; array('image_button'),
  );


The theme function that renders that form element is theme_image_button(). Changing the value of #theme_wrappers, you can alter the way your form element is rendered.
Keep in mind that theme wrappers, as any other theme functions, need to be declared with hook_theme().