Drupal 8: Custom Theming 101

Drupal is a CMS(Content Management system) that allows us to create content-driven sites. The Theme in Drupal is a collection of files that is responsible for the look and feel of your site. Theme developers use HTML, CSS, JavaScript, and other front-end assets to design the site. It may contain one or more sub-themes.  Sub-themes are the child themes that inherit the properties of the parent theme.

Drupal8 provides some of the default core themes like Bartik, sevenUsing existing themes is a great way, but what if it doesn’t satisfy customer specific needs? Here, the custom themes come into play.  We can create a custom theme as a base-theme or as a sub-theme.

In this blog, we will create our own custom theme using Drupal’s Bootstrap base theme. For that first, we need to download the Bootstrap theme and extract it into <root folder>/themes/{contrib}. To create a custom theme, you will need to place it at /themes/{custom}. It is good practice to place the contributed themes in a subfolder named contrib.

Before starting, we need to know how a complete D8 theme structure looks like.

| |-custom
| | |-themename
| | | |-config
| | | | |-install
| | | | | |-themename.settings.yml
| | | | |-schema
| | | | | |-themename.schema.yml
| | | |-css
| | | | |-style.css
| | | |-js
| | | | |-business.js
| | | |-images
| | | | |-buttons.png
| | | |-templates
| | | | |-block.html.twig
| | | | |-comment.html.twig
| | | | |-html.html.twig
| | | | |-maintenance-page.html.twig
| | | | |-node.html.twig
| | | | |-page.html.twig
| | | |-favicon.ico
| | | |-logo.png
| | | |-screenshot.png
| | | |-themename.breakpoints.yml
| | | |
| | | |-themename.libraries.yml
| | | |-themename.theme
  • .info.yml: this file gives information about your theme
  • .libraries.yml: defines external 3rd party javascript files, internal JS and CSS files which we will learn more in STEP-2.
  • .breakpoints.yml: defines the points to fit different screen devices.
  • .theme: The PHP file that stores conditional logic and data preprocessing of the variables before they are merged with markup inside the .html.twig file.
  • /css: All CSS files related to themes are placed in this folder. The files must be defined in the info, and libraries file to operate.
  • /js: All js files related to themes are placed in this folder. Must be defined in the info, and libraries file to operate.
  • /images: where you theme images are stored. It is a good practice to put images in this folder.
  • /includes: where 3rd-parties libraries (like Bootstrap, Foundation, Font Awesome, etc) are put. It is a good practice to store them in this folder
  • /templates: where all your template files (ones that provide HTML markup of your theme page) are placed.
  • logo.png: your theme logo if you’re using one.
  • favicon.ico:  you’re theme favicon if you’re using one.
  • screenshot.png: your theme screenshot that will be displayed in the admin/appearance.

Theme Layout Display

Firstly, we should decide how the website layout looks. We are going to make it really simple. As shown below, your Drupal template will consist a header, sidebar, content area, and footer.

Now let’s move to the main part – to create a simple responsive Drupal 8 template that extends Bootstrap base theme.


STEP-1: Defining a theme with a .info.yml file file provides meta-data about your theme to Drupal. Create the .info.yml file in the root of your theme folder. The folder should have the same name as the .info.yml file. So if your theme is named “foo” then the folder is named “foo/” and the file .info.yml  is named “foo/“. Remember to choose a theme name which is not already being used by a module or a different theme.


The following key/value pairs provide meta-data about your theme and define some of the basic functionality.
1. name(required): Name of the theme which will appear on the “Appearance” page where the theme is activated.

2. type(required): Provides the type of extension(like a theme, module or profile).

3. description(optional): Description of a theme which will be displayed on the appearance page.

4. core(required): The major version of Drupal core that is supported

5. package(optional):  Allows to group the themes together. Since we are creating a custom theme we group them in Custom package.

6. libraries(optional):  A list of libraries (which contains CSS, JS, and 3rd party libraries) to add to all pages where the theme is active. we will discuss more on libraries in step 2

7. base theme: It is recommended to specify the base theme from which the custom theme is inheriting the resources. If not defined, Drupal will use “Stable” as your base theme. In our example, the base theme is the bootstrap theme.

8. regions(optional):  Define the regions of the theme where you place your blocks. If not declaring any regions in the .info.yml file, Drupal will use the default regions of the core. Keep in mind that if you define at least one region, default regions are no longer applied.

name: Foo
type: theme
description: 'A modern responsive theme.'
core: 8.x
package:  Custom
  - foo/global-styling
  - foo/global-js
base theme: bootstrap
  header: Header
  content: Content
  sidebar_first: 'Sidebar first'
  footer: Footer

Adding regions to your theme:

A region is basically a section of the page of your theme. You can define as many regions as you wish on your .info.yml file. And the next step you have to update your page.twig file to inform the new regions.

Regions are rendered in the page template file, which will be covered in STEP 4.2.

STEP-2: Creating .libraries.yml file

Define all of your asset libraries in a THEMENAME.libraries.yml  file in your theme folder. Each “library” in the file includes external third-party libraries, JS and CSS files.

  version: 1.x
      css/style.css: {}
     js/foo.js: {}

Most themes will use global-styling/global-js asset library, for the  (CSS files)/ (js files) to be loaded on every page where the theme is active.

To include a new library

The below example includes a new library called bxslider. We have bundled the CSS(bxslider.css) and JS(bxslider.js) files that will be required within this bxslider library.

        css/bxslider.css: {}
    js/bxslider.js: {}

Dependencies can be added to a  library, like if we want to load jQuery for this particular library declare the dependency with an extension name followed by a slash, followed by the library name, in this case core/jquery

        css/bxslider.css: {}
    js/bxslider.js: {}
    - core/jquery

To Include 3rd party libraries using CDN:

JS can also come from an external URL or from included CSS files.

For Example: To include Bootstrap library from external URL:

  version: 1.4.4
    name: MIT
    gpl-compatible: true
  js: { type: external, minified: true } { type: external, minified: true } { type: external, minified: true }
    theme: { type: external, minified: true }
Attach libraries to pages

We can do it in three different ways:

1. Attach a library to the twig template:  For example, if we want to attach a flex slider library to a particular template, we can use an attach_library() function in any *.html.twig.

{{ attach_library('THEMENAME/flexslider') }}

2. Attaching a library to all pages: Declare the library in

name: foo
type: theme
core: 8.x
  - foo/flexslider

3. Attaching the library to a subset of pages:  In order to attach the library to a particular page, implement THEMENAME_preprocess_HOOK() function in the .theme file.

function foo_preprocess_HOOK(&$variables) {
  $variables['#attached']['library'][] = 'foo/flexslider';

STEP-3: Creating .theme file

The THEMENAME.theme file is a PHP file in which all preprocess function is written. Preprocess functions allow Drupal themes to manipulate the variables that are used in Twig template files by using PHP functions t0 preprocess data before it is exposed to each template. All of the dynamic content available to theme developers within a Twig template file is exposed through a preprocess function.

Preprocess functions follow a specific naming convention THEMENAME_preprocess_HOOK() where HOOK is the name of the template file for which you want to preprocess data. An argument has to be passed to the preprocess function. The argument usually named $variables is an associative array and is passed by reference so that you can manipulate the data it contains. The keys of this array are used in the respective twig templates.

For example, the preprocess function for node.html.twig would be THEMENAME_preprocess_node(). Since our custom theme is foo, the preprocess function would be as below:

function foo_preprocess_node(&$variables){
 $variables['base_path'] = base_path();
 $variables['theme_path'] = \Drupal::theme()->getActiveTheme()->getPath();
 $variables['view_mode'] = $variables['elements']['#view_mode'];
 $variables['node'] = $variables['elements']['#node'];

In node.html.twig, we will render the variables of the preprocess function as below:

<p>{{ base_path }}</p>

In addition to the template-specific preprocess functions, there is another function, THEMENAME_preprocess(&$variables, $hook) that is called for every single template file. It consists of the second argument which is hook or template name.

STEP-4: Templating

Twig is a template engine for PHP and replaces PHPTemplate as the default templating engine.Template files are responsible for the HTML markup of every page generated by Drupal. Any file ending with the .html.twig extension is a template file. These files are composed of standard HTML markup as well as tokens used by the Twig template engine to represent dynamic content that will be substituted into the HTML markup when the template is used.

Let’s browse through some of the core template file functions.

html.html.twig – defines HTML markup of the site
page.html.twig – defines every page on the site
node.html.twig – defines every node on the site
region.html.twig – defines every region on the site
block.html.twig – defines every block on the site
field.html.twig – defines every dynamic element on the site

4.1 Override template files

Drupal provides default template files in the core folder which provides a minimal set of markup that can be overridden and all the changes can be made to the copy of the original rather than changing the template file provided by Drupal, another theme, or a contributed module.Overriding can be done by

  1. locating which template to be used from the parent theme.
  2. copying that template to your theme.
  3. modify the template as required.


For Example, if you want an HTML markup for a node, copy the node.html.twig from parent theme to your custom theme template folder(themes/THEMENAME/templates) and modify accordingly. Look for theme debugging to know which file to be overridden and for file suggestions.

4.2 Adding regions to templates

In order to display content in a particular region, you’ll need to make sure your new regions are also added to your file page.html.twig. Regions will be represented as Twig variables whose name corresponds with the key used in your file with the string page. prepended.


In your

header: 'Header'

In page.hml.twig

{{ page.header }}


<div class="page">
 {% if page.header %}
       {{ page.header }}
 {% endif %}
 {% if page.content%}
       {{ page.content}}
 {% endif %}
 {% if page.footer%}
       {{ page.footer}}
 {% endif %}

4.3 Twig Debugging

Drupal provides theme name suggestions to know which template file needs to be overridden in any particular case. For that, go to root/sites/default/services.yml. Inside that file, you will find a setting for Twig debug. This setting will be set to false by default. Simply change it to true as shown in the image below:

If services.yml is not present in your folder, copy  and save as services.yml in your root/sites/default folder. Now, clear your cache after making this change. When we return to our page and inspect the markup we will find debugging information added in the form of code comments. Here’s an example of what our homepage markup will look like when inspected in DevTools:

As you can see, the debug info provides the path to the new template file we have created. This information is repeated for other template files found on the page, providing a fast and easy way of finding the file you need to override or edit.

STEP-5: Install the theme

In the Manage administrative menu, navigate to Appearance(admin/appearance). The Appearance page appears. Locate our custom theme under uninstalled themes and click on install and set as default to use it.

Follow the above steps to create your own custom theme and customize it accordingly. HAPPY THEMING!!!!!!!!!!!!!!!!!!

About The Author

Leave a Reply