2024 August

Override Form Twig Templates in Drupal 8+ (example: Commerce Cart Form)

Sometimes you want to add a layout to a Drupal form, but the form.html.twig has only the “children” variable by default, which holds rendered markup.

In order to make single form components available in the Twig template, you have to use hook_theme().

Firstly, thanks to Ruslan Piskarov, whose article pushed me in the right direction: https://makedrupaleasy.com/articles/drupal-10-how-render-any-form-twig-template

As an example, I use the Drupal Commerce „Cart Form“, which basically holds all contents on the cart page (views_form_commerce_cart_form_default).

In your THEMENAME.theme file, add hook_theme() like so:

/**
 * Implements hook_theme().
 */
function drowl_child_theme($existing, $type, $theme, $path) {
  return [
    'views_form_commerce_cart_form_default' => [
      'render element' => 'form',
      'path' => $path . '/templates/commerce/cart',
    ],
  ];
}

‚views_form_commerce_cart_form_default‘ needs to be your BASE_FORM_ID.

The ‚render element‘ is the name of the render array variable.

The path is optional, if you are fine with putting the template right into your „templates“ folder.

In this example, the resulting Twig file needs to be /templates/commerce/cart/views-form-commerce-cart-form-default.html.twig.

The template looks like this:

{#
/**
  * @file
  * Default theme implementation for a 'form' element.
  *
  * Available variables
  * - attributes: A list of HTML attributes for the wrapper element.
  * - children: The child elements of the form.
  *
  * @see template_preprocess_form()
  *
  * @ingroup themeable
  */
#}

{# {{ dump(form) }} #}
<div class="commerce-cart">
  <form{{ attributes }}>
    <div class="row">
      <div class="col col-md-8">
        <div class="commerce-cart__line-item-box">
          {{ form|without(
            'footer',
            'actions',
            'paypal_smart_payment_buttons'
          ) }}
        </div>
      </div>
      <div class="col col-md-4 commerce-cart__actions-sum">
        {{ form.actions }}
        <a href="/" class="btn btn-outline-dark btn--block">{{ 'Products Overview'|t }}</a>
        {{ form.paypal_smart_payment_buttons }}
        {{ form.footer }}
      </div>
    </div>
  </form>
</div>

Thats it, happy coding!