How to render a form in custom template in Drupal 8 and 9
Here we are going to discuss how to render custom form in a twig template.
Here first we are rendering entire form in a twig template. And then rendering each field by field in twig template.
Here we have a module dn_studentslist module.
See below steps for creating a form and rendering form in a twig template.
Step 1
Create below rout in dn_studentslist.routing.yml file and map to the form StudentForm.
dn_studentslist.add_student: path: '/add/students' defaults: _title: 'Add Students' _form: '\Drupal\dn_studentslist\Form\StudentForm' requirements: _access: 'TRUE'
Step 2
Create a form in module path \Src\Form\StudentForm.php.
<?php namespace Drupal\dn_studentslist\Form; use Drupal\Core\Form\FormBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Database\Database; use Drupal\Core\Url; use Drupal\Core\Routing; /** * Provides the form for adding countries. */ class StudentForm extends FormBase { /** * {@inheritdoc} */ public function getFormId() { return 'dn_student_form'; } /** * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { $form['fname'] = [ '#type' => 'textfield', '#title' => $this->t('First Name'), '#required' => TRUE, '#maxlength' => 20, '#default_value' => '', ]; $form['sname'] = [ '#type' => 'textfield', '#title' => $this->t('Second Name'), '#required' => TRUE, '#maxlength' => 20, '#default_value' => '', ]; $form['age'] = [ '#type' => 'textfield', '#title' => $this->t('Age'), '#required' => TRUE, '#maxlength' => 20, '#default_value' => '', ]; $form['marks'] = [ '#type' => 'textfield', '#title' => $this->t('Marks'), '#required' => TRUE, '#maxlength' => 20, '#default_value' => '', ]; $form['actions']['#type'] = 'actions'; $form['actions']['submit'] = [ '#type' => 'submit', '#button_type' => 'primary', '#default_value' => $this->t('Save') , ]; $form['#theme'] = 'students_add_form'; return $form; } /** * {@inheritdoc} */ public function validateForm(array & $form, FormStateInterface $form_state) { //print_r($form_state->getValues());exit; } /** * {@inheritdoc} */ public function submitForm(array & $form, FormStateInterface $form_state) { $get_path_update = explode("/", \Drupal::service('path.current')->getPath()); $field = $form_state->getValues(); $re_url = Url::fromRoute('dn_studentslist.add_student'); $fields["fname"] = $field['fname']; $fields["sname"] = $field['sname']; $fields["age"] = $field['age']; $fields["marks"] = $field['marks']; \Drupal::messenger()->addMessage($this->t('Student data=fname='.$fields["fname"].'=sname='.$fields["sname"].'=age='.$fields["age"].'marks==='.$fields["marks"])); $form_state->setRedirectUrl($re_url); } }
Please note we are passing template name in below line before return form variable.
$form[‘#theme’] = ‘students_add_form’;
In this form we are just submitting student name mark and age and displaying submitted data in same form.
Step 3
Create hook_theme function and provide your form template details in your module file or .theme file as below.
/** * @file * Implementing our hooks. */ /** * Implements hook_theme(). */ function dn_studentslist_theme($existing, $type, $theme, $path) { return [ 'students_list' => [ 'variables' => ['students' => [], 'title' => ''], ], 'students_add_form' => [ 'render element' => 'form', ], ]; }
Here students_add_form is the form twig template here, students__list is another template.
If you have only one form template, hook_theme return be provided as below.
return [ 'students_add_form' => [ 'render element' => 'form', ], ];
Step 4
Create a twig template as below in path /templates/
Here template name will be students-add-form.html.twig
Below code in twig prints entire form in above twig template.
<div class="row custom-form"> <div class="col-md-6"> {{ form }} </div> </div>
After submission you will get below message in twig template.
You cans see custom-form class in div while inspecting this page.
Step 5
Here we are printing each form field in twig template
So in our students-add-form.html.twig file, first we have to print form hidden fields.
So print below variables first.
{{ form.form_build_id }}
{{ form.form_token }}
{{ form.form_id }}
If we are not printing this , save button of the form will not work.
Next, print each fields in form as below.
{{ form.fname }}
{{ form.sname }}
{{ form.age }}
{{ form.marks }}
{{ form.actions.submit }}
So finaly code in twig template will be as below.
{{ form.form_build_id }} {{ form.form_token }} {{ form.form_id }} <div class="row custom-form"> <div class="col-md-6"> </div> <div class="col-md-6"> {{ form.fname }} {{ form.sname }} {{ form.age }} {{ form.marks }} {{ form.actions.submit }} </div> </div>
In our StudentForm.php, we have submit button inside $form[‘actions’] . so we have to use {{ form.actions.submit }} in order to print submit button.
Now we can access the page /add/students
So here submit action is returning success message with all details.
Download sample source code here.