Working With Twig Templates

Last updated on
7 October 2025

Drupal allows you to override all of the templates that are used to produce HTML markup so that you can fully control the markup that is shown as output within a custom theme. There are templates for each page element ranging from high-level HTML to small fields.

There are many ways to change the markup in Drupal, see for example Why is so hard to make custom twig templates for Drupal? where different methods are shared, such as via Views UI or Twig templates, using the modules Twig Tweak or Twig Field Value. See Getting Drupal 8/9 Field Values in Twig and 10 Twig Tricks for Better Drupal Theming for more tips.

Overriding templates

You can override Drupal core templates or contributed modules templates by adding templates to your theme folder that follow a specific naming convention.

To override templates you need to:

  1. Locate the template you wish to override.
  2. Copy the template file from its base location into your theme folder.
  3. (optionally) Rename the template according to the naming conventions in order to target a more specific subset of areas where the template is used.
  4. Modify the template to your liking.

Once you copy a template file into your theme and clear the cache, Drupal will start using your instance of the template file instead of the base version.

You can find out what templates are in use for any part of the page by using the Twig debugging tools.

Get more specific Twig suggestions

If you want to make changes to an element, but only some places, and need more specific template suggestions for forms and elements such as buttons, input field, labels, etc., you can use these modules:

There's also Themable forms, though it may get migrated into another module and deprecated, see #3057386: Merge into Twig Template Suggester.

Theme hook suggestions

Sometimes you want to make changes to a template file, but only for some of the places that it's used. A common example is making changes to the node template file for only nodes of a specific type. Drupal's theme layer allows you to target specific use cases of a template file by following a specific naming convention. When rendering an article node Drupal will first look for the node--article.html.twig template file and use it if it exists. If it doesn't, Drupal will fall back to the default node.html.twig template. The process by which Drupal determines what possible names a template file could use is called theme hook suggestions.

Theme hook suggestions allow you to implement targeted overrides in your theme for template files with a specific naming convention.

All layers from the core, modules, theme engines, and themes can provide suggestions. You can add or modify suggestions using the hooks:

For best results, here are a couple of tips. The $suggestions array elements should only be submitted with underscores, not hyphens. Identify the needed theme hook (the Twig debugger mode will show this in your browser HTML source). Then only use that string plus two underscores, then your additional custom statement. For example, if the theme hook is called 'bob,' inside your YOURTHEME.theme file:

function YOURTHEME_theme_suggestions_bob_alter(array &$suggestions, array $variables, $hook) {
  $element = $variables['element'];
  $settings = $element['#settings'];
  if (!empty($settings['field_name'])) {
    $suggestions[] = 'bob__' . strtr($settings['field_name'], '-', '_');
  }
}

Use strtr function to clean out any hyphens and replace them with underscores. Note that theme suggestions require prefixing the suggestion with the original theme hook, followed by two underscores, eg $suggestions[] = 'bob__' . . If using something other than the theme hook is used as a prefix, eg.  $suggestions[] = 'bobstring__' ., the twig template may not load due to the suggestion not being prefixed with the original theme hook. 

Rebuild cache

When working with theme hook suggestions, there is a possibility that Drupal uses its cache rather than the new templates as suggested. Clear the cache if you experience this problem. To clear the cache, choose one of the methods described in Clearing Drupal's cache.

Background information

You can think of the suggestions as naming hints telling the system to pick and choose based on the right circumstances.

The template suggestions are set through theme suggestion hooks which can be altered. These hooks allow any module or theme to provide alternative theme functions or template name suggestions and reorder or remove suggestions provided by hook_theme_suggestions_HOOK() or by earlier invocations of this hook.

How Drupal determines page theme hook suggestions based on path

Here is another explanation based on the theme_get_suggestions() function:

The list of possible templates for a given page is generated by Drupal through the theme_get_suggestions() function, which is called by the system_theme_suggestions_page() function.

The Drupal path of the page is first broken up into its components. As mentioned above, the Drupal path is the canonical path; aliases are not considered, there is one and only one Drupal path for a page. For example, the URLs "http://www.example.com/node/1/edit" and "http://www.example.com/mysitename?q=node/1/edit", have the same Drupal path of node/1/edit, with its components being node, 1, and edit.

After adding the node template suggestions to the suggestions list, suggestions are calculated for the page template. For every component, the following logic is followed:

  1. If the component is a number, the prefix plus __% is added to the list of suggestions.
  2. Regardless of whether the component is a number or not, the prefix plus __ plus the component is added to the list of suggestions.
  3. If the component is not a number, the prefix plus __ plus the component is added to the list of suggestions.

After the list of components is iterated through, if the page is the front page (as set through "Administration > Configuration > System > Site information."), then page__front is added to the list of suggestions.

Note that eventually, to turn a suggestion into an actual file name, __ gets turned into --, and .html.twig gets appended to the suggestion. Thus, for node/1/edit, we get the following list of suggestions:

  1. page.html.twig (this is always a suggestion)
  2. page--node.html.twig (and prefix is set to page__node)
  3. page--node--%.html.twig
  4. page--node--1.html.twig (prefix is not changed because the component is a number)
  5. page--node--edit.html.twig (and prefix is set to page__node__edit)
  6. page--front.html.twig (but only if node/1/edit is the front page)

When the page is actually rendered, template overrides are searched starting with the last suggestion in the list. If a template file exists for the suggestion, that template is used. Otherwise, the previous suggestion in the list is checked for a template, and so on. If none of the overriding suggestions exist, page.html.twig is the final suggestion.

Note: This explains why page--front.html.twig, will always take priority over other possible templates; this template matches the last suggestion provided in the list, and therefore overrides any other suggestion for the front page.

How to add a page template for a content type

Drupal does not automatically detect page templates for content types purely based on the naming convention. To add a page template for a content type, add this in your example.theme file (replace "example"):

/**
 * Implements hook_theme_suggestions_page_alter().
 */
function example_theme_suggestions_page_alter(array &$suggestions, array $variables) {
  if ($node = \Drupal::routeMatch()->getParameter('node')) {
  $suggestions[] = 'page__' . $node->bundle();
  }
}

Now, you get suggestions in the source for content type as well. Before:

<!-- FILE NAME SUGGESTIONS:
   * page--node--336.html.twig
   * page--node--%.html.twig
   * page--node.html.twig
   x page.html.twig
-->

After (with the file page--article.html.twig also created) in the source:

<!-- FILE NAME SUGGESTIONS:
   x page--article.html.twig
   * page--node--336.html.twig
   * page--node--%.html.twig
   * page--node.html.twig
   * page.html.twig
-->

Differences with Drupal 7

Previously to alter template suggestions, you altered $variables['theme_hook_suggestion'] and $variables['theme_hook_suggestions'] in preprocess functions to introduce theme suggestions. Since Drupal 8, modules and themes now define and alter theme suggestions in their own dedicated hooks.

More information

Change record New hooks for theme suggestions.

Help improve this page

Page status: No known problems

You can: