Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll

Creating Custom Twig Templates for a Custom Module

13/04/2025, by Ivan

Menu

The general idea in Drupal 8 is that you want to avoid generating HTML directly in the PHP code of your custom module. Instead, you want this to go into Twig templates. To create new Twig templates in your module, follow these steps.

Step #1: Define hook_theme in your .module file
Create a [module].module file if it doesn’t already exist, and add the code that defines each of your Twig templates. The key of each item in the array is what you will need to call the template later. Do not use dashes in the file name.

function test_twig_theme($existing, $type, $theme, $path) {
  return [
    'my_template' => [
      'variables' => ['test_var' => NULL],
    ],
  ];
}

See the documentation for hook_theme().

Step #2: Call the template
Wherever you return your render array (from a controller method called via your routing yml file, or elsewhere), call the Twig template. Here's an example from a test module called via a routing yml file. (More info needed for that part)

/**
 * @file
 * Contains \Drupal\test_twig\Controller\TestTwigController.
 */
 
namespace Drupal\test_twig\Controller;
 
use Drupal\Core\Controller\ControllerBase;
 
class TestTwigController extends ControllerBase {
  public function content() {
    return [
      '#theme' => 'my_template',
      '#test_var' => $this->t('Test Value'),
    ];
  }
}

You can also use the render method to build output if you need to use this as part of another workflow in your code:

$renderable = [
  '#theme' => 'my_template',
  '#test_var' => 'test variable',
];
$rendered = \Drupal::service('renderer')->renderPlain($renderable);

Keep in mind this is a basic implementation with no caching. The Render API Overview docs provide more info on how to add caching to this. Speaking of caching — variable names are cached, so if you change them (say, from “test_var” to “my_var”), you’ll need to rebuild cache.

Step #3: Create the Twig template
Inside your module, in the templates folder, create the Twig template. The file name should match what you used in hook_theme() (replace underscores with dashes). In this case, the file name would be my-template.html.twig.
Here’s the file I used for testing:

Test twig template!

test_var: {{ test_var }}

The beauty of this is that the template file defined in your module will be used if there isn’t one already in your theme. Just place the file in your theme’s templates folder, clear the cache (drush cache-rebuild), and it will read that file instead.

You can place the file in any nested subfolder of your site theme to keep things organized.

Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.