Newer Post

DrupalCon Latin America Through the Eyes of an X-Teamer (Part 1)

Older Post

Never stop growing as a developer

Deep Dive into the Anatomy of Drupal 8 Theming

Drupal 8 is the most advanced Drupal ever built and it will surely will be a game changer among other CMSes out there. Part of its strength comes from adopting the principles from other technologies like Symfony, YAML, Twig, and Backbone.js.

The theming has undergone many changes since Drupal 7, especially the deep integration with Twig – a popular templating engine for PHP, which opens the door to more robust, scalable and secure themes.

Note that since Drupal 8 is still under active development, some of the details below may change prior to its release. Still, since Drupal 8 is now feature-frozen, hopefully most info should remain relevant.

These are several things to note about the changes for theming in Drupal 8, and we will discuss each of these further in the next section:

  • a.
    The use of *.info.yml file as a replacement for *.info file is definitely giving more options and flexibility on the theme configuration.
  • b. yourtheme.libraries.yml
    This a configuration file to define assets for your theme – notably for css and javascript files.
  • c. yourtheme.breakpoints.yml
    This a configuration file to setup breakpoints for your responsive custom theme.
  • d. yourtheme.theme
    This file contains all of the preprocess functions, similar to the *template.php *file in Drupal 7.
  • e. Twig template file (.html.twig)
    The usage of Twig as mentioned above gives more robustness on the front-end. The *new
    syntax is cleaner and addresses a lot of common security pitfalls. Usually all the *.html.twig files are put under the *templates *sub-folder.

Here is a screenshot for the basic folder structure for the theme:

Screen Shot 2015-03-24 at 15.32.55


This is the first file that you need to set up for your theme. This file is equivalent to the *.info file in Drupal 7, providing meta-data about your theme.

Consider this yaml code below:

These are the basic keys *along with *values that need to be provided:

  • name: YourTheme Required. The human readable name will appear on the Appearance page, where you can activate your theme.
  • description: 'A Cool theme by you.'
    Required. The description is also displayed on the Appearance page.
  • type: theme Required. The type key indicates the type of extension, e.g. module, theme or profile. For themes this should always be set to “theme”.
  • package: Custom The package key allows you to group themes together on the Appearance page.
  • base theme: classy The theme can inherit the resources from another theme by defining it as a base theme. classy in this case is the name of the base theme.
  • core: 8.x Required. The core key specifies the version of Drupal core that your theme is compatible with.
  • screenshot: yourtheme.png With the screenshot key you define a screenshot that is shown on the Appearance page. If you do not define this key then Drupal will look for a file named ‘screenshot.png’ in the theme folder to display.
  • libraries:

The libraries key can be used to add asset libraries — which can contain both CSS and JS assets — to all pages where the theme is active. From the example above, yourtheme is the name of the custom theme, followed by / (slash) and global-styling is the name of value to reference the library that we setup in the file of yourtheme.libraries.yml (will discuss further below).

Basically a container for the block that can be added.Above we see some basic key: ’value’ being defined. Taken from the example above: header is the region system name, and ‘Header’ is the name of the region that will display in the admin page.

YAML has significant whitespace, so remember to check the INDENTATION, otherwise an error will occur.

b. yourtheme.libraries.yml

This file contain references to the assets – notably is the CSS and JavaScript files that needs to be loaded from your theme.

This is the basic setup of what could be contained in the *.libraries.yml file.

The global-styling and custom-stuff here can act as a container for the defined assets. And you’ve noticed that we have 2 containers of libraries here.

When you include the libraries in the *.info.yml (ie: file, please note that the naming should be in this format:

where yourtheme is the name of your custom theme followed by / (slash), and global-styling and custom-stuff is the name of the libraries that you want to include (see a. section above).

You can define as many containers as you need.

Each library’s container follows a similar pattern, as explained below:

Above is a basic setup where we defined 3 css files, all of them located in the sub-folder called css under the yourtheme (see screenshot below for reference). The last one is set specifically to one type of media which is print.

Screen Shot 2015-03-26 at 16.20.14

JavaScript files are set up similarly to css files. Here we defined 2 javascript files located in the sub-folder of js under yourtheme (see screenshot below for reference).

Screen Shot 2015-03-26 at 16.23.43

c. yourtheme.breakpoints.yml

Breakpoints are basically the point where a website will adjust the theme or layout based on the browser widths by using media query in css.

The purpose of this configuration file is to define the breakpoints for your custom theme, so other (contributed/custom) modules or/and theme that has features and/or functionality related with the breakpoints will be able to access the configuration and use it accordingly.

For example, with the Responsive image module, the module uses the breakpoints that are defined in the custom theme. Below is a screenshot of the admin page of the Responsive image module where you can specify Image styles based on the defined breakpoints in the custom theme.

Screen Shot 2015-04-03 at 23.18.25

In order to setup the breakpoints configuration, you need to create a file called yourtheme.breakpoints.yml, with basic code as shown below:

Each section represents one breakpoint, which consists of a unique machine name (ie:,* yourtheme.narrow, yourtheme.wide*), with properties explained below:

  • label A human readable label for the breakpoint.
  • mediaQuery Media query proper syntax.
  • weight Order for the breakpoints to take place.
  • multipliers Supported pixel resolution multipliers.

For more info about breakpoints configuration for a custom theme, please refer to this page.

d. yourtheme.theme

This file contains the hookpreprocess to alter or make modification to the theme. This file serves the same purpose as *template.php *in Drupal 7.

Below is a simple example of code on how to add custom assets library to our custom theme.

function yourtheme_preprocess_page(&$variables) {  
      $variables['#attached']['library'] = array('yourtheme/global-styling', 'yourtheme/custom-stuff');

As you can see we use hook_preprocess_page(), and we add global-styling and custom-stuff via the #attached library array that comes from $variables.

e. Twig template file (*.html.twig)

Another significant change introduced in Drupal 8 is the use of the popular PHP templating engine Twig, to replace the PHPTemplate-based theme system in Drupal 7.

For example, if you used to have page.tpl.php in Drupal 7, it has now been replaced by page.html.twig in Drupal 8.

For the sake of easy management, Twig template files are put under the templates sub-directory from your custom theme.

Here is a list of possible Twig template files that are available in Drupal 8 by default.

HTML (template)

  • html.html.twig

Page template

  • page.html.twig
  • page–node.html.twig
  • page–node–.html.twig, ie: page–node–1.html.twig
  • page–node–edit.html.twig


  • region.html.twig
  • region–.html.twig, ie: region–right-sidebar.html.twig


  • block–.html.twig, *ie:block–cust-mod.html.twig
  • block–.html.twig, ie: block–cust-mod–1.html.twig


  • node.html.twig
  • node–.html.twig, *ie:node–article.html.twig
  • node–.html.twig, ie: node–.html.twig

Taxonomy terms

  • taxonomy-term.html.twig
  • taxonomy-term–.html.twig
  • node–.html.twig, ie: node–.html.twig, ie: *taxonomy-term–ingredients.html.twig*
  • taxonomy-term–.html.twig, ie: *taxonomy-term–1.html.twig*


  • field–.html.twig, ie: *field–long-text.html.twig*
  • field–.html.twig, ie: *field–phone-number.html.twig*


  • comment.html.twig
  • comment-wrapper.html.twig


For forum containers:

  • forums–containers.html.twig
  • forums–.html.twig
  • forums–containers–.html.twig

For forum topics:

  • forums–topics.html.twig
  • forums–.html.twig
  • forums–containers–.html.twig

Maintenance page

  • maintenance-page.html.twig

Search result

  • search-result.html.twig

In terms of coding, Twig template files in Drupal 8 are not much different to PHPTemplate files in Drupal 7. In both cases you’re essentially writing HTML. The difference is how you define variables and define conditional logic within it.

Here are some examples:



     * @file
     * File description


     * @file
     * File description


Printing a variable:
PHPTemplate:<div class="content"><?php print $content; ?></div>
Twig:<div class="content">{{ content }}</div>

Printing a hash key item:
PHPTemplate:<?php print $item['#item']['alt']; ?>
Twig:{{ item['#item'].alt }}

Assigning a variable:
PHPTemplate:<?php $custom_var = $content->comments; ?>
Twig:{% set custom_var = content.comments %}

Assigning an array:
PHPTemplate:<?php $args = array('!author' => $author, '!date' => $created); ?>
Twig:{% set args = {'!author': author, '!date': created} %}


PHPTemplate:<?php if ($content->comments): endif; ?>
Twig:{% if content.comments %} {% endif %}

PHPTemplate:<?php if (!empty($content->comments)): endif; ?>
Twig:{% if content.comments is not empty %} {% endif %}

PHPTemplate:<?php if (isset($content->comments)): endif; ?>
Twig:{% if content.comments is defined %} {% endif %}

PHPTemplate:<?php if ($count > 0): endif; ?>
Twig:{% if count > 0 %} {% endif %}

Control structures:

PHPTemplate:<?php foreach ($users as $user) {} ?>
Twig:{% for user in users %} {% endfor %}


PHPTemplate:<?php print check_plain($title); ?>
Twig:{{ title|striptags }}

PHPTemplate:<?php print t('Home'); ?>
Twig:{{ 'Home'|t }}

Translate with substitutions:
PHPTemplate:<?php print t('Welcome, @username', array('@username' => $user->name)); ?>
Twig:{{ 'Welcome, @username'|t({ '@username': }) }}

For more examples please refer to the Twig homepage.

And that wraps it up! That should be enough to know about the basic changes to theming in Drupal 8, and enough to get you started on your own exploration and experimentation.

X-Team is hiring Drupal developers! Click here to learn how to join the league of the extraordinary.


We'll help you unleash.

Join the 20,000 developers who subscribe to our newsletter.

Scale your
Development team

We help you execute projects by providing trusted developers who can join your team and immediately start delivering high-quality code.

Hire Developers
code, drupal