Implementing custom forms

Submitted by victor.bourgade on Sat, 02/03/2018 - 21:00

The principle is to make an upper layer in the form template which will be called by the basic form and rendered in replacement of it.

Let's see how to do that for login and registration forms :

First, you'll have to implement a theme hook to tell that you want to make an upper layer for the form.

In your .theme file just insert :

  function THEMENAME_theme() {
      return array(
        'user_login' => array('render element' => 'form'),
        'user_pass' => array('render element' => 'form'),
      );
 }

So, we basically tell to drupal that when rendering user_login and user_pass form it has to wrap elements into $form variable which will make our upper layer.

Next step is to tell drupal that it has to look in a new template file for the respective forms.

In your .theme file :

 function THEMENAME_form_user_login_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
   $form['#theme'] = 'user_login';
 }
 function THEMENAME_form_user_pass_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
   $form['#theme'] = 'user_pass';
 }

We just alter the forms to make them load a new template file when called.

And voilà, now you just have to make two templates files with the name you gave them, here :

user-login.html.twig & user-pass.html.twig

Note that underscores are translated into hyphens in file names. 

Let's see what's inside user-login.html.twig :

{#
/**
 * Exemple of twig template for user-login
 */
#}
<form{{ attributes }}>
  <div class="account-input-wrapper">
     <div>{{ form.name }}</div>
      <div>{{ form.pass }}</div>
    {{ form|without('name', 'pass') }}
  </div>
</form>

As you can see, the trick reside in calling the entire form at the end of the file without the values you called. The aim is to print all validation fields needed by drupal. If you don't do that you'll be likely to get an error when submiting the form. 

This methodology can be applied to any other form. You'll be able to get your field with {{ form.field_name }}. Don't forget to print the entire form without the value you called manually.

 

About the writer

victor.bourgade

Victor is a web developer passionnated in drupal and bootstrap technologies. He likes challenges and beautiful designs.

When not behind his computer you'll find him drinking beers with friends or in the middle of nowhere hiking with his dog.