Following the question Generating <button type="submit"> with the form API for Drupal 7 I tried to implement the same thing in Drupal 8.

I need the following output:

<button type="submit" class="clearfix"><span>Login</span></button>

So I tried to use this code:

$form['submit'] = array(
  '#prefix' => "<button type ='submit'>",
  '#suffix' => "</button>",
  '#type' => 'markup',
  '#markup' => "<span>" . t('Login') . "</span>",

But I obtain this:


But if I use this code:

$form['submit'] = array(
  '#prefix' => "<b>",
  '#suffix' => "</b>",
  '#type' => 'markup',
  '#markup' => "<span>" . t('Login') . "</span>",

I obtain this:


So the <button> tag is eliminated but the <b> tag not. Very strange for me, the Button is not rendered.

Thanks to @Kevin I used the leymannx answer an with this code I solve the problem:

$form['submit'] = [
  '#type' => 'inline_template',
  '#template' => '<button type="submit" class="glyphicon glyphicon-search"></button>',

But, why I can't use the same code in Drupal 7 and Drupal 8 to generate a button with FAPI?

  • Have you tried adding the span to your prefix and suffix? "<b><span>" ... What's the point of the span anyways? are you trying to inline stuff?
    – No Sssweat
    Mar 15, 2017 at 1:22
  • Check that link for two potential solutions
    – Kevin
    Mar 15, 2017 at 1:24
  • @NoSssweat The front-end developper want this "<button type="submit" class="clearfix"><span>Login</span></button>" in the page, but if you use the code that works in Drupal 7 it doesn't works in Drupal 8. Mar 15, 2017 at 2:56
  • 1
    @Kevin thanks, yes the leymannx answer (drupal.stackexchange.com/a/230031/28275) solve my problem, I will edit my question to see if we can find why this has changed. Mar 15, 2017 at 2:59
  • 1
    @AdrianCidAlmaguer don't forget to up vote laymannx ;-)
    – No Sssweat
    Mar 15, 2017 at 3:06

1 Answer 1


The reason why it is not working in Drupal 8 as in Drupal 7 is, that prefix and suffix are passed to xssFilterAdminIfUnsafe() function in doRender() function. Thus preventing all tags except the tags specified in $adminTags.

Excerpt from doRender:

  // We store the resulting output in $elements['#markup'], to be consistent
  // with how render cached output gets stored. This ensures that placeholder
  // replacement logic gets the same data to work with, no matter if #cache is
  // disabled, #cache is enabled, there is a cache hit or miss.
  $prefix = isset($elements['#prefix']) ? $this->xssFilterAdminIfUnsafe($elements['#prefix']) : '';
  $suffix = isset($elements['#suffix']) ? $this->xssFilterAdminIfUnsafe($elements['#suffix']) : '';

  $elements['#markup'] = Markup::create($prefix . $elements['#children'] . $suffix);

You can use '#allowed_tags' property to enable specific tags. So this should work:

  $form['submit'] = array(
  '#type' => 'markup',
  '#markup' => "<button type ='submit'><span>" . t('Login') . "</span></button>",
  '#allowed_tags' => ['button', 'span'],  

But '#allowed_tags' property will not work for '#prefix' and '#suffix'.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.