Hi there!

Although I'm new to Drupal, I have experience in various PHP frameworks, ExpressionEngine and CraftCMS development.

I'm trying to build a custom module that renders a form, and so far I managed to get it rendered in the route defined in the module.routing.yml file (mysite.com/my_module/my_route) but I don't understand how you include it in a template/view (page or a custom one).

Do I need to create something like a custom field?? or a Block??

Could anyone maybe point me to a more comprehensive tutorial, I've been reading a lot of documentation, but to be honest haven't really found anything that makes sense to me.

Thank you very much.

Comments

Shashwat Purav’s picture

Check the link below:

Send a form to twig template

This might help.

Thank You,
Shashwat Purav

dzanfardino’s picture

Thank you Shashwat,
I had already found that page, and tried it without having it working. There must be some basics concepts I'm missing. Where do I define the pageAction() method ? In the Form or in the module Controller? and what do I assign to "#theme" ? Can I for instance pass "page" ? ? and also I read somewhere else you have to define a hook_theme function, but again, it's not clear how and where.

I wonder, do the Drupal developers follow a different paradigm? If there is a more common and maybe better way to achieve the same results I'd be more than happy to learn it.

Thank you very much!

jmsosso’s picture

Hello,

You need to implement hook_theme() in your .module file to define a new theme implementation, set the #theme key in your form to the name of your implementation and create a twig template with this same name, but replacing hyphens with underscores:

example.module

function example_theme() {
  return [
    'my_awesome_form' => [
      'render element' => 'form',
    ],
  ];
}

Form/MyAwesomeForm.php

class MyAwesomeForm extends FormBase {
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form = parent::buildForm($form, $form_state);

    $form['#theme'] = 'my_awesome_form';
    [...]

templates/my-awesome-form.html.twig

{{ form.form_build_id }}
{{ form.form_token }}
{{ form.form_id }}

<div class="row">
  <div class="col-md-6">
    {{ form.name }}
  </div>
  <div class="col-md-6">
    {{ form.address }}
  </div>
</div>
[...]

In this example form.name and form.address are your form fields, the array keys that you used to create the form, and I used bootstrap markup to show them in two columns.

UPDATE: form tag is not necessary in this template, because Drupal adds a theme wrapper to the form that take care of create this tag with the right attributes. I also discover that if the id of the form is equal to the name of the theme function you dont'n need to include the line $form['#theme'] = 'my_awesome_form'.

Hope this helps.
Regards.
www.servinube.net

Jaypan’s picture

That's really useful information, but it's not what the original post was looking for. The user wasn't looking for how to theme a form, but rather how to render a form within a template (that has other elements other than the form).

Still, it's likely that people trying to figure out how to theme forms may end up on this page, so it's good that the information is here.

filipe_carvalho’s picture

Hello @jmsosso I am trying to place a contact form linked to a content type "product" already created, in Drupal 8.
All good with link between product and contact form, I already added contact storage module to save forms.

But, I am having problems with forms, when I want to create a costume twig template named node--produto--full.html.twig to customize the view of product and form.
I don't know how I can write twig template field by fields, because sometime I need to write the tag "form" and write action and method, witch came from form "attributes" but writing attributes from node prints node attributes not form attributes, like this "data-drupal-form-fields="edit-subject-0-value,edit-message-0-value,edit-submit"

Is there any way to print, or bring form attributes to write on tag form, or I need to write this template in a different way?

Here is a example of my template node--produto--full.html.twig

<article{{ attributes }}>
    <div class="row">
        <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
            {{ title_prefix }}
            {% if not page %}
                <h2{{ title_attributes }}>
                    <a href="{{ url }}" rel="bookmark">{{ label }}</a>
                </h2>
            {% endif %}
            {{ title_suffix }}
        </div> 
    </div>

    <div class="row">
        <div class="col-lg-8 col-md-8 col-sm-8 col-xs-12">
            {{ content.field_produto_imagem }}
        </div>
        <div class="col-lg-4 col-md-4 col-sm-4 col-xs-12">
            <div id="produto-full-descricao">
                {{ content.field_produto_descricao }}
            </div>
            <div id="produto-full-detalhe" style="padding: 10px 0px;">
                {{ content.field_produto_detalhe }}
            </div>
            <div id="produto-full-contact-button">

                {% set form  = content.field_contact[0] %}       

                <form {{form.attributes }}>
                    {{ form.form_build_id }}
                    {{ form.form_token }}
                    {{ form.form_id }}
                    {{ form.subject }}
                    {{ form.message }}


                    <div class="actions">
                        {{ form.actions.submit }}
                    </div>
                </form>


                <button type="button" class="btn btn-primary">Contactos</button>
            </div>
        </div>
    </div>
</article>  
dotmundo’s picture

You should examine one of the theme templates but as I understand your question, you are asking more about how to pass the fields and attributes from your custom form to the template. Remember this sample code that was given earlier:

function example_theme() {
  return [
    'my_awesome_form' => [
      'render element' => 'form',  // 'form' is a variable name and can be anything you want.
    ],
  ];
}

So what this is saying is that for this custom theme, take the fields you defined in your custom form and map them to the template under the 'form' name. So in other words, if you change 'form' to 'cat', then your template must be altered to so that your fields begin with the variable called, 'cat'. So form.subject must be cat.subject.

If you want to see all of the variables that are available in your template, put {{ dump() }} at the top or bottom of your TWIG file and in your services.yml, turn on debugging.

Rob230’s picture

I am surprised there is no theme hook suggestion for form by form ID.

It would be nice if we could override form.twig.html with something like form--id.twig.html.

TMulhearn’s picture

Can someone tell me, what if you want to render a form in a twig footer file ? Would still have to create a separate twig file for the form ?

dotmundo’s picture

You should study any Drupal theme that implements a search input box in the footer and/or how blocks work and laid out.

TMulhearn’s picture

Thanks for the tip. Ended up using a custom block for the form, and dropping the block in the region i needed it in.

vjsutar’s picture

I have done something like this and its working fine.

mymodule.module

/**
 * Implement hook_theme
 *
 */
function mymodule_theme($existing, $type, $theme, $path) {
    return array(
        'custom_form' => array(
            'variables' => array(
                'my_form' => NULL
            ),
            'render element' => 'form'
        ),
    );
}

mymoduleController.php

$form = \Drupal::formBuilder()->getForm('Drupal\[module_name]\Form\[FormNameClass]');

      return array(
          '#theme' => 'custom_form',
          '#my_from' => $form,
      );

mymodule/templates/custom-form.html.twig

{{ my_from }}
gulshan kumar’s picture

Hello Jimososso

I have an html page that have an header and footer,sidebar ,an html form . i want convert it into drupal theme .will you please all the steps converting it into drupal theme and i have to insert data in to database. Actually i am facing problem in converting to twig file .please explain all steps.

Thanks.

IndrajithKB’s picture

Please watch this

https://www.youtube.com/watch?v=xdifbN3y5hU

i hope this really helpfull to you.

sankarprakash’s picture

-If you want to theme your form in D8 and disable the cache:

    $form['#theme'] = 'newsDetail'; //(This twig file need to be present in your module folder)

    $form['#cache'] = ['max-age' => 0];

function your_module_theme($existing, $type, $theme, $path) {

   return array(

                                'newsListPage' => array(

                                  'variables' => array(

                                                'news_details_array' => array(), // If you are passing a variable

                                                ),

                                ),

                                'newsDetail' => array(

                                                'render element' => 'form',

                                ),

                );

}

In theme (html.twig), {{ form.rowIndex['#value'] }} and {{ form.cartTbl[key].code['#markup'] }} we will use for display

Ruslan Piskarov’s picture

In my blog, I wrote a very short article, how to theming any Drupal 8 form in 5 mins by using own twig template with own markup. Maybe it will helpful for anyone.

Visit my blog for more info: Make Drupal Easy.

ressa’s picture

Thanks for sharing @Ruslan Piskarov, it is surprisingly hard to find a simple, working example for rendering forms in a custom Twig file, but your article was just what I was looking for, and I could theme my form in Bootstrap with Twig with your help. A few observations, which might help others:

To find the the form ID, it can be defined like this in a .php file, where custom_datacollection is the form ID:

public function getFormId() {
  return 'custom_datacollection';
}

You can also find it by disabling caching and enabling Twig debugging, then look for this in the source, right before the form:

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'custom_datacollection' -->

Finding the right hook_form_alter() combination can be tricky, but if your theme machine name is theme_2023 and form ID custom_datacollection, then the hook_form_alter() call should be made for THEMENAME_form_FORMID_alter like this:

function theme_2023_form_custom_datacollection_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {

Add a Twig file in templates/custom-datacollection.html.twig -- note: use a dash, not underscore!

vensires’s picture

Instead of using a custom theme function, you could always use a custom twig template - if preferable.

Add the following code in your module or theme:

/**
 * Implements hook_theme_suggestions_HOOK_alter() for form().
 */
function MYTHEME_theme_suggestions_form_alter(&$suggestions, array $variables) {
  $suggestions[] = 'form__' . $variables['element']['#form_id'];
}

Then, if for example you want to override the user edit form, you would have to create a file named form--user-form.html.twig in your theme's templates folder.

In most cases, a theme function might be better suited but, just in case, I leave it here as an alternative.

mlncn’s picture

And Twig Template Suggester module can provide these suggestions without the need for adding your own suggestions alter.  It's nice to ensure the suggestions are standard across your projects!

benjamin, Agaric