Drupal Theme Anatomy — .info.yml, Twig Templates and Libraries
In this tutorial, you'll learn the anatomy of a Drupal theme — from the .info.yml file and Twig templates to the libraries.yml for CSS and JavaScript and the regions configuration that defines where content appears.
What You'll Learn
- The complete folder structure of a Drupal theme
- How the .info.yml file defines a theme's identity and capabilities
- Configuring regions where blocks and content appear
- Defining asset libraries in libraries.yml for CSS and JavaScript
- Understanding template files and their naming conventions
Why It Matters
Every Drupal theme, whether custom or contributed, follows the same structural conventions. Understanding theme anatomy lets you create custom themes, modify existing ones, and troubleshoot layout issues. Without this knowledge, you are limited to what contributed themes provide. With it, you can build any design you imagine. The theme layer is where Drupal's backend content meets the frontend presentation, and knowing how it works gives you complete control over your site's appearance.
Real-World Use
A design agency builds custom Drupal themes for university clients. Each theme follows the same structural foundation: a .info.yml file declares the theme, a libraries.yml file loads the CSS framework (Bootstrap or Tailwind), Twig templates render the HTML, and regions define where navigation, content, and sidebars appear. This consistent anatomy lets the agency quickly spin up new themes while maintaining code quality and performance standards across projects.
Learning Path
flowchart LR A[URL Aliases] --> B[Theme Anatomy] B --> C[Installing Themes] C --> D[Twig Templating] D --> E[Sub-themes] E --> F[Template Suggestions] F --> G[Asset Libraries] G --> H[Module Management]
Theme Folder Structure
A Drupal theme lives in the themes directory. Custom themes go in themes/custom, contributed themes in themes/contrib.
themes/custom/mytheme/
├── mytheme.info.yml
├── mytheme.libraries.yml
├── mytheme.breakpoints.yml
├── mytheme.schema.yml
├── screenshot.png
├── logo.svg
├── css/
│ ├── style.css
│ ├── components/
│ │ └── header.css
│ └── layout/
│ └── grid.css
├── js/
│ ├── main.js
│ └── navigation.js
├── templates/
│ ├── page.html.twig
│ ├── node.html.twig
│ ├── block.html.twig
│ ├── field.html.twig
│ ├── region.html.twig
│ └── system/
│ ├── breadcrumb.html.twig
│ └── pager.html.twig
├── images/
│ └── background.jpg
└── config/
└── install/
└── mytheme.settings.yml
The .info.yml File
The .info.yml file is the most important file in a theme. It declares the theme to Drupal and contains all metadata and configuration.
# mytheme.info.yml
name: 'My Custom Theme'
type: theme
core_version_requirement: ^10 || ^11
description: 'A custom Drupal theme built for the university website.'
package: Custom
version: 1.0.0
base theme: false
libraries:
- mytheme/global
- mytheme/fonts
regions:
header: 'Header'
primary_menu: 'Primary Menu'
secondary_menu: 'Secondary Menu'
page_top: 'Page Top'
page_bottom: 'Page Bottom'
highlighted: 'Highlighted'
featured_top: 'Featured Top'
breadcrumb: 'Breadcrumb'
content: 'Content'
sidebar_first: 'Left Sidebar'
sidebar_second: 'Right Sidebar'
footer: 'Footer'
regions_hidden:
- page_top
- page_bottom
Key Properties
- name: Human-readable name shown on the Appearance page
- type: Must be
themefor themes - core_version_requirement: Specifies which Drupal versions the theme supports
- base theme: Set to
falsefor a standalone theme, or the machine name of a base theme for sub-themes - libraries: Asset libraries loaded on every page
- regions: Named areas where blocks can be placed
- regions_hidden: Regions that should not appear in the block layout UI
The .libraries.yml File
The libraries file defines CSS and JavaScript assets that can be loaded selectively.
# mytheme.libraries.yml
global:
version: 1.0
css:
base:
css/base/elements.css: {}
layout:
css/layout/grid.css: {}
component:
css/components/header.css: {}
css/components/navigation.css: {}
css/components/footer.css: {}
theme:
css/style.css: {}
js:
js/main.js: {}
js/navigation.js:
attributes:
defer: true
fonts:
version: 1.0
css:
theme:
//fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap:
type: external
minified: true
homepage:
version: 1.0
css:
component:
css/components/hero.css: {}
js:
js/hero-animation.js: {}
CSS Categories (SMACSS)
Drupal organizes CSS using SMACSS categories:
- base: Reset styles, element defaults (CSS reset, normalize)
- layout: Grid systems, page structure, container widths
- component: Reusable UI components (buttons, cards, headers)
- state: State-specific styles (active, disabled, hidden)
- theme: Theme-specific visual customization (colors, fonts)
JavaScript Options
- header: Set to
trueor omit to load in<head> - footer: Set to
trueto load before closing</body> - attributes: HTML attributes like
deferorasync - minified: Set to
truefor already-minified files
Declaring Libraries in .info.yml
Any library defined in .libraries.yml can be loaded globally by listing it in .info.yml:
libraries:
- mytheme/global
- mytheme/fonts
To load a library on specific pages only, use the Twig attach_library() function in the template:
{{ attach_library('mytheme/homepage') }}
Regions Configuration
Regions define where content appears on the page. The page.html.twig template renders regions in the order defined.
regions:
header: 'Header'
primary_menu: 'Primary Menu'
highlighted: 'Highlighted'
content: 'Content'
sidebar_first: 'Left Sidebar'
sidebar_second: 'Right Sidebar'
footer: 'Footer'
Each region renders in page.html.twig using the page variable:
<header>
{{ page.header }}
{{ page.primary_menu }}
</header>
<main>
{{ page.highlighted }}
<div class="content-wrapper">
<article>
{{ page.content }}
</article>
<aside>
{{ page.sidebar_first }}
{{ page.sidebar_second }}
</aside>
</div>
</main>
<footer>
{{ page.footer }}
</footer>
Template Files
Templates use Twig syntax and control how each piece of content renders.
Essential Templates
- page.html.twig — The overall page layout wrapper
- node.html.twig — Renders individual content items (articles, pages)
- block.html.twig — Renders blocks placed in regions
- field.html.twig — Renders individual fields on entities
- region.html.twig — Renders a region containing blocks
- html.html.twig — The HTML document wrapper
Template Suggestions
Drupal uses a suggestion system to allow template overrides for specific content:
node.html.twig → Default node template
node--article.html.twig → Template for Article nodes
node--article--full.html.twig → Template for Article nodes in full view mode
node--article--teaser.html.twig → Template for Article nodes in teaser view
node--123.html.twig → Template for a specific node by ID
Preprocess Functions
Preprocess functions in the .theme file let you add variables to templates.
<?php
// mytheme.theme
function mytheme_preprocess_node(&$variables) {
$node = $variables['node'];
// Add a custom variable based on node type.
if ($node->bundle() === 'article') {
$variables['is_article'] = true;
$variables['reading_time'] = ceil(str_word_count(strip_tags($node->body->value)) / 200);
}
}
function mytheme_preprocess_page(&$variables) {
// Add active theme path variable.
$variables['theme_path'] = \Drupal::service('extension.list.theme')->getPath('mytheme');
}
Breakpoints Configuration
Breakpoints define Responsive Design thresholds for responsive image styles.
# mytheme.breakpoints.yml
mytheme.small:
label: Small
media: '(min-width: 0px)'
weight: 0
multipliers:
- 1x
mytheme.medium:
label: Medium
media: '(min-width: 768px)'
weight: 1
multipliers:
- 1x
mytheme.large:
label: Large
media: '(min-width: 1024px)'
weight: 2
multipliers:
- 1x
- 2x
Theme Schema
Schema files define the structure of theme settings, enabling the settings form UI.
# mytheme.schema.yml
mytheme.settings:
type: theme_settings
label: 'My Custom Theme settings'
mapping:
font_family:
type: string
label: 'Font Family'
container_width:
type: string
label: 'Container Width'
show_sidebar:
type: boolean
label: 'Show Sidebar'
accent_color:
type: string
label: 'Accent Color'
social_links:
type: sequence
label: 'Social Links'
sequence:
type: mapping
mapping:
platform:
type: string
label: 'Platform'
url:
type: uri
label: 'URL'
Theme Screenshot
A screenshot.png image at the root of the theme folder appears on the Appearance page. The recommended size is 293 pixels wide by 68 pixels tall.
# Generate a screenshot using ImageMagick:
convert -size 293x68 gradient:blue screenshot.png
Theme Hooks
The hook_theme function in your .theme file defines custom theme hooks that templates can implement.
<?php
function mytheme_theme($existing, $type, $theme, $path) {
return [
'mytheme_card' => [
'variables' => [
'title' => NULL,
'body' => NULL,
'image' => NULL,
'link' => NULL,
],
'template' => 'templates/card',
],
];
}
This creates a card.html.twig template that can be called from other templates:
{{ include('mytheme-card', {
title: 'Hello World',
body: 'This is a card component.',
image: 'card-image.jpg',
link: url('entity.node.canonical', {'node': 123})
}) }}
Common Mistakes
Missing the .info.yml file: Without this file, Drupal does not recognize the theme at all. Double-check the filename matches your theme's machine name.
Incorrect regions array format: Regions must use machine names as keys and human-readable labels as values. A missing region causes blocks assigned to that region to disappear.
Not clearing cache after adding templates: Drupal caches template information. After adding new template files, clear the cache with
drush crto see changes.Using wrong CSS category in libraries.yml: Putting component styles in the
basecategory can override other theme styles. Use the correct SMACSS category for each file.Forgetting to declare libraries in .info.yml: Defining a library in libraries.yml does not automatically load it on every page. It must be listed in the
librarieskey of .info.yml or attached viaattach_library()in Twig.
Practice Questions
What is the purpose of the .info.yml file in a Drupal theme, and what are five key properties it must define?
How do SMACSS categories (base, layout, component, state, theme) help organize CSS in a Drupal theme?
What happens if a block is placed in a region that is not defined in the theme's .info.yml file?
Challenge: Design a theme structure for a magazine website. Define the folder layout, choose five regions, create a .info.yml file, a .libraries.yml with at least three libraries (global, magazine, homepage), and describe which template files you would override to customize article pages.
FAQ
Mini Project
Goal: Create a basic custom theme structure.
- Create a folder
themes/custom/mytheme/ - Create
mytheme.info.ymlwith name, type, description, and three regions: header, content, footer - Create
mytheme.libraries.ymlwith a global library containing style.css and main.js - Add
screenshot.png(293x68 pixels) - Create
templates/page.html.twigthat renders the header, content, and footer regions - Create
templates/node.html.twigthat renders the node title and body - Enable the theme on the Appearance page
- Verify the theme works and blocks can be placed in your custom regions
What's Next
Now that you understand theme anatomy, proceed to installing and managing themes to learn about contributed themes and base themes. After that, explore Twig templating in depth.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro