Julien Fontvieille 

Creating a Drupal theme from scratch: where to start?

Creating a Drupal theme from scratch by Julien Fontvieille, Drupal front-end developer

When working on a Drupal project, you have the choice between using an existing theme or building one from scratch. In most agency projects, the theme already exists and does not need to be recreated. In this article, we will look at how to create a custom theme when no existing theme is available.

Why create a custom theme rather than using an existing one?

Drupal offers ready-to-use contrib themes such as Olivero (the default theme) or Bootstrap. These can be useful for prototypes or projects without a strict visual identity, but they have their limitations.

In an agency context, we work from precise mockups, usually created in Figma or Adobe XD. Adapting an existing theme to a custom design often means spending more time undoing what has already been done than rebuilding the theme from scratch. Starting from a blank theme gives you full control over the rendering, the generated HTML and the performance.

This is also what sets an experienced Drupal front-end developer apart: knowing how to build a clean foundation, free of technical debt from the very start.

The minimal structure of a Drupal theme

A custom Drupal theme relies on two essential files, placed in a dedicated folder under /themes/custom/theme_name/. It is very important to place your theme folder inside the custom directory, otherwise Drupal will not offer the option to activate your theme, as it will not detect it.

The .info.yml file is the theme's identity card, without it, Drupal will not recognise the theme either. This file can contain the list of your HTML regions, your libraries, your dependencies, and more. Here is the basic information to fill in for my_theme.info.yml :
name: My Theme
type: theme
description: 'Custom theme for the project'
core_version_requirement: ^10 || ^11
base theme: false
libraries:
- my_theme/global

The .libraries.yml file declares the CSS and JS files that Drupal should load. This information is referenced in the .info.yml file, under the libraries section. Drupal does not load anything automatically, everything must be declared in my_theme.libraries.yml :

global:
  css:
    theme:
      css/style.css: {}
  js:
    js/main.js: {}
  dependencies:
    - core/drupal

If your styles or scripts are not showing up, remember to clear the Drupal cache after every modification to these files. Drupal caches library declarations.

The basic file structure looks like this:

my_theme/
├── my_theme.info.yml
├── my_theme.libraries.yml
├── css/
│   └── style.css
├── js/
│   └── main.js
└── templates/

Integrating your first Twig templates

Once the theme is activated, you can start overriding Drupal's Twig templates. All base templates are found in Drupal core, the idea is to copy them into your theme's templates/ folder and modify them from there.

If you are not yet comfortable with Twig, I recommend reading my dedicated article on Twig on Drupal before continuing.

The templates most commonly overridden first:

  • page.html.twig : overall page structure
  • node.html.twig : content rendering
  • block.html.twig : block rendering
  • html.html.twig : base HTML structure, the <html> and <head> tags

To target a specific content type, Drupal uses a suggestion system. For example, node--article.html.twig will apply only to content of the "article" type. Drupal looks for the most specific template first, then works its way back up to the most generic. If you are certain a page will only be used once, you can include the node ID directly in the file name for maximum precision.

To find out which template Drupal is trying to load on a given page, enable Twig debug mode in your services.yml file:

parameters:
  twig.config:
    debug: true

Once enabled, Drupal displays comments in your browser's HTML source that indicate exactly which templates are being used and which suggestions are available. This is the most useful day-to-day tool for a Drupal front-end developer.

Managing styles: SCSS and Drupal libraries

Drupal does not compile SCSS natively, you will need an external tool such as npm with an SCSS watcher, or a task runner like Gulp. Visual Studio Code, the IDE I use, has extensions that handle this compilation. The compiled file is then declared in .libraries.yml.

A common SCSS structure for a Drupal theme:

scss/
├── base/
│   ├── _variables.scss
│   └── _reset.scss
├── components/
│   ├── _header.scss
│   └── _card.scss
├── layout/
│   └── _grid.scss
└── style.scss

The style.scss file imports everything else. The compiled style.css file is the one declared in .libraries.yml.

Two classic mistakes to avoid:

  • Forgetting to clear the Drupal cache after modifying .libraries.yml, changes will not take effect without it.
  • Declaring multiple libraries without attaching them to the right templates, a library declared in .info.yml under libraries is loaded globally across the entire site, which can unnecessarily slow down pages.

To attach a library to a specific template only, use {{ attach_library('my_theme/my_library') }} directly in the relevant .html.twig file.

Intégrateur web à Lyon - Julien Fontvieille

Contact Me

Interested in my profile? Want to know more about me? I’d be delighted to talk with you! Feel free to get in touch!