Drupal 8: How to render any form in a Twig Template

5 Aug.2016
Theme a form in drupal 8

Every form trying to use theme equals their machine name. You can find this template name in $form['#theme'] just by altering, it is always (or in most times) same as form id machine name. What you need to do is register a template for it. You need to implement hook_theme() You can write it in CUSTOMMODULE.module or in THEMENAME.theme. Theme key must be the same as in $form['#theme'], so it's automatically use it, otherwise you need to add the new one via form alter.

File
THEMENAME.theme
/**
 * Implements hook_theme().
 */
function easydrupal_theme($existing, $type, $theme, $path) {
  return [
    'contact_message_feedback_contact_form_form' => [
      'render element' => 'form',
    ],
  ];
}
 
/**
 * Implements hook_form_alter().
 *
 * @param $form
 * @param \Drupal\Core\Form\FormStateInterface $form_state
 * @param $form_id
 */
function THEMENAME_form_contact_message_feedback_contact_form_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
 
  // Checking field type because it is markup for logged user and we wan't any placeholder.
  if (isset($form['name']) && $form['name']['#type'] == 'textfield') {
    $form['name']['#attributes']['placeholder'][] = $form['name']['#title'] . ' *';
    unset($form['name']['#title']);
  }
 
  if (isset($form['mail']) && $form['mail']['#type'] == 'email') {
    $form['mail']['#attributes']['placeholder'][] = t('Your email') . ' *';
    unset($form['mail']['#title']);
  }
 
  if (isset($form['subject']['widget'])) {
    $form['subject']['widget'][0]['value']['#attributes']['placeholder'][] = $form['subject']['widget'][0]['#title'] . ' *';
    unset($form['subject']['widget'][0]['value']['#title']);
  }
 
  if (isset($form['message']['widget'])) {
    $form['message']['widget'][0]['value']['#attributes']['placeholder'][] = t('Message') . ' *';
    unset($form['message']['widget'][0]['value']['#title']);
  }
 
}
File
contact-message-feedback-contact-form-form.html.twig
<div class="row">
    <div class="col-sm-6">
        {{ form.name }}
        {{ form.mail }}
        {{ form.subject }}
    </div>
    <div class="col-sm-6">
        {{ form.message }}
    </div>
</div>
<div class="row">
    <div class="col-sm-12">
        {{ form.captcha }}
        {{ form.actions }}
        {# Renders the rest of the form #}
        {{ form|without('name', 'mail', 'subject', 'message', 'actions', 'captcha') }}
    </div>
</div>

Assume we use a bootstrap theme and the site has bootstrap.css, if not, you can create own CSS rules.

Conclusion

As you can see, the implementation is very simple. In this way, you can do the theming for any form, for example, contact form of the site or Views Exposed Filters form with a custom twig file. You have the total control on rendering a form in a Twig template.