Render custom button

Sometimes for our front-end development we need to have very granular control about how our form buttons being rendered. So instead of standard drupal markup we want to have something like

<button class="bird-guide-zip-submit button pea-green">
  <span class="hide-for-medium hide-for-large hide-for-xlarge">
     <i class="icon-magnifier"></i>
  </span>
  <span class="hide-for-tiny hide-for-small">Ok</span>
</button>

You would think that something like:

$form['submit'] = array(
  '#type' => 'button',
  '#value' => '<span class="hide-for-medium hide-for-large hide-for-xlarge">
      <i class="icon-magnifier"></i>
    </span>
    <span class="hide-for-tiny hide-for-small">' . t('Ok') . '</span>',
  '#attributes' => array(
    'class' => array('bird-guide-zip-submit', 'button', 'pea-green'),
  ),
);

would do the job but that is not the case as #value is being sanitized (that is great from security perspective). In order to change this behavior for one particular button we should use

 '#theme_wrappers' => array('mymodule_button'),

And then define your custom theming function

/**
 * Implements hook_theme().
 */
function mymodule_theme() {
  return array(
    'mymodule_button' => array(
      'render element' => 'element',
    ),
  );
}
 
/**
 * Custom button theming function.
 */
function theme_mymodule_button($variables) {
  $element = $variables['element'];
 
  $element['#attributes']['type'] = 'submit';
  element_set_attributes($element, array('id', 'name'));
  $element['#attributes']['class'][] = 'form-' . $element['#button_type'];
  return '<button' . drupal_attributes($element['#attributes']) . '>' . $element['#value'] . '</button>';
}

Be aware that when you use this technique you take responsibility for making sure you do not display any potentially harmful html in the #value as you do not sanitize it.