Creating Themes and Subthemes
In Drupal 10 you can create base themes and subthemes. A base theme provides some set of predefined styles and functionality that a frontend developer can base a subtheme upon. Any theme can be used as a base theme, even if it is a subtheme of some other theme.
Core Themes
Drupal 10 comes with several preloaded themes, located in core/themes/
.
- Olivero: Olivero is a core theme and the new default theme for Drupal starting with version 9.4.0.
- Claro: A clean, accessible and powerful administration theme based on the Drupal Design System.
- Stark: Is not based on any other theme. It is intentionally styleless to demonstrate default Drupal HTML, CSS and Javacript from core and contrib modules.
- Starterkit: The recommended approach for creating new themes. This is a command line tool which allows theme developers to easily start a new theme. For more information, consult the Starterkit documentation on Drupal.org.
- Stable9: This is a hidden, minimal base theme which serves as a default for new themes created via the Starterkit theme creation method.
Choosing a Base Theme
Choosing a base theme is a big decision when creating a new Drupal theme as it lays the framework for the way you will be building your frontend. Olivero
and Claro
are the two standard base themes provided out of the box, although you could technically use Stable9
and Stark
as a base theme if you really wanted to.
The reason Drupal 10 provides two base themes is to appeal to two different groups of developers:
- Developers who want sensible markup and default classes to apply CSS with minimal overrides.
- Developers who want a minimalist theme that doesn't place unnecessary markup and css upon themers.
Stark
was established for the minimalists, and Olivero
was for those wanting sensible markup and classes.
But these are only two out of a theoretically infinite number of base themes you can choose from, including a custom base theme that is shared by all of your different projects.
You can also create a completely custom theme, but keep in mind that by doing so you are no longer guaranteeing backwards compatibility when core functionality changes.
File Structure
Custom and third-party themes should be installed in `/themes/.
It is best practice to store themes in the following folder structure:
- Contributed themes should go in the
themes/contrib
folder. - Custom themes should go in the
themes/custom
folder.
Inside each theme it is recommended to have css
, js
and images
directories.
The info.yml file
Drupal automatically searches the themes directory looking for {themename}.info.yml
. This file provides information about your theme to Drupal.
For example - mytheme.info.yml
:
name: MyTheme
type: theme
description: 'A subtheme'
core: 10.x
libraries:
- substable/global-styling
- substable/global-scripts
base theme: stable9
regions:
header: Header
content: Content
sidebar_left: 'Sidebar - Left'
sidebar_right: 'Sidebar - Right'
footer: Footer
Theme Keys
Here is a list of available theme keys from Defining a theme with an .info.yml file:
- name (required) The human-readable name. This will appear on the "Appearance" page where the theme is activated.
- type (required) Indicates the type of extension, i.e., "module", "theme", or "profile". For themes this should always be set to "theme". This value is case-sensitive.
- base theme (required) A theme can inherit the resources from another theme by specifying it as a base theme. It is recommended to use the Starterkit method. If set to false, no base theme is being used. *(note, if you change the base theme, uninstall and reinstall the theme to ensure that the new base theme is correctly registered and enabled). *Note: Use the machine name of the base theme.
- core_version_requirement (required) Allows modules, themes, and profiles to specify that they are compatible with multiple major versions of Drupal core. Using
>=9.2
marks it as compatible with all versions of core from 9.2 and onward. - description (optional) The description, displayed on the "Appearance" page.
- dependencies (optional) List of machine names of other themes necessary to be present and installed to get this theme installed. The base theme is not necessary to get listed here in extra.
- package (optional) Specifies a "package" that allows you to group themes together.
- core (required for Drupal 8) Specifies the version of Drupal core that the theme is compatible with. It can be omitted if you specify core_version_requirement and don't support Drupal 8.7.7 and below.
- php (optional) The minimum version of PHP required. Defaults to the value of
DRUPAL_MINIMUM_PHP
constant. version *(optional)*Specifies a version. For themes hosted on drupal.org, the version number will be filled in by the packaging script. Do not specify it manually, but leave out the version line entirely. - libraries (optional) A list of libraries (which can contain both CSS and JavaScript assets) to add to all pages where the theme is active. [Read more about themes and asset libraries.
- libraries-override (optional) A collection of libraries and assets to override. Read more at Overriding and extending libraries.
- libraries-extend (optional) A collection of libraries and assets to add whenever a library is attached. Read more at Overriding and extending libraries.
- hidden (optional) Indicates whether to hide the theme from the "Appearance" page so that it cannot be enabled/disabled via the UI.
- engine (optional) The theme engine. Defaults to "twig".
- logo (optional) The path to logo relative to the theme's
.info.yml
file. By default, Drupal will look for a file named "logo.svg" in the root of your theme folder and use that as the theme's logo. - screenshot (optional) The path to screenshot relative to the theme's
.info.yml
file. Screenshots should be 588 pixels wide and 438 pixels high, though they are displayed at a smaller size. By default, Drupal will look for a file named "screenshot.png" in the root of your theme folder and use that as the theme image on the "Appearance" page. - regions (optional) A list of theme regions. (Note that region keys are not preceded by a dash.) A
content
region is required. Read more about adding regions to a theme. - regions_hidden (optional) A list of inherited regions to remove.
- features (optional) A list of features to expose on the theme "Settings" page.
- ckeditor_stylesheets (optional) A list of stylesheets to add to the CKEditor frame.
- ckeditor5-stylesheets (optional) A list of stylesheets to add to the CKEditor5 frame.
The libraries.yml file
If you wish to include JavaScript and CSS in your theme, you can do so by creating libraries in {themename}.libraries.yml
.
For example - substable.libraries.yml
:
global-styling:
version: 1.x
css:
theme:
css/style.css: {}
css/print.css: { media: print }
global-scripts:
version: 1.x
js:
js/substable.js: {}
dependencies:
- core/jquery
Libraries also need to be included in the {themename}.info.yml
file. See substable.info.yml
example above.
See the JavaScript/jQuery section for more information about JavaScript and attaching libraries to a subset of pages.
Breakpoint Module
The breakpoints
module allows you to predefine breakpoints for use in your responsive design. Breakpoints are defined in a {themename}.breakpoints.yml
file.
Here is an example from the bootstrap theme:
bootstrap.screen-xs-max:
label: screen-xs-max
mediaQuery: 'all and (max-width: 767px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-sm-min:
label: screen-sm-min
mediaQuery: 'all and (min-width: 768px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-sm-max:
label: screen-sm-max
mediaQuery: 'all and (max-width: 991px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-md-min:
label: screen-md-min
mediaQuery: 'all and (min-width: 992px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-md-max:
label: screen-md-max
mediaQuery: 'all and (max-width: 1199px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-lg-min:
label: screen-lg-min
mediaQuery: 'all and (min-width: 1200px)'
weight: 1
multipliers:
- 1x
From Working with breakpoints in Drupal:
Please note that inputting your CSS breakpoints into your breakpoints.yml
file is only necessary when Drupal needs to interact with the breakpoints as in the case of the Responsive Images module.
Breakpoint Keys
- label - A human readable label for the breakpoint.
- mediaQuery - Media query text proper, e.g. 'all and (min-width: 851px)'.
- weight - Positional weight (order) for the breakpoint.
- multipliers - Supported pixel resolution multipliers.
Breakpoint Groups
From Working with breakpoints in Drupal 10:
Breakpoints can be organized into groups. Modules and themes should use groups to separate out breakpoints that are meant to be used for different purposes, such as breakpoints for layouts or breakpoints for image sizing.
yourtheme.group1.mobile:
label: narrow
mediaQuery: ''
weight: 0
multipliers:
- 1x
group: yourtheme.group1
yourtheme.group1.narrow:
label: narrow
mediaQuery: '(min-width: 560px)'
weight: 0
multipliers:
- 1x
- 2x
group: yourtheme.group1
yourtheme.group1.wide:
label: wide
mediaQuery: '(min-width: 851px)'
weight: 1
multipliers:
- 1x
- 2x
group: yourtheme.group1
yourtheme.group2.mobile:
label: narrow
mediaQuery: ''
weight: 0
multipliers:
- 1x
group: yourtheme.group2
yourtheme.group2.narrower:
label: narrow
mediaQuery: '(min-width: 400px)'
weight: 0
multipliers:
- 1x
- 2x
group: yourtheme.group2
yourtheme.group2.wider:
label: wide
mediaQuery: '(min-width: 1001px)'
weight: 1
multipliers:
- 1x
- 2x
group: yourtheme.group2
You can also add breakpoints to breakpoint groups defined by other modules or themes, but you must use the full name.
yourmodule.yourtheme.group2.superwide
label: superwide
mediaQuery: '(min-width: 1501px)'
weight: 1
multipliers:
- 1x
- 2x
group: yourtheme.group2
Adding Regions to a Theme
All regions should be declared in the theme info file. Regions are not inherited from the base theme. The keys match the machine name and the values match the label for each available region.
For example:
regions:
header: Header
content: Content
sidebar_left: 'Sidebar - Left'
sidebar_right: 'Sidebar - Right'
footer: Footer
Then each region can be referenced in your page.html.twig
file with curly braces:
<div class="container">
{% if page.header %}
<div class="row">
<div class="header col-xs-12">
{{ page.header }}
</div>
</div>
{% endif %}
<div class="row">
{% if page.sidebar_left %}
<div class="sidebar-left col-xs-2">
{{ page.sidebar_left }}
</div>
{% endif %}
{% if page.sidebar_left and page.sidebar_right %}
<div class="content col-xs-8">
{{ page.content }}
</div>
{% elseif page.sidebar_left or page.sidebar_right %}
<div class="content col-xs-10">
{{ page.content }}
</div>
{% else %}
<div class="content col-xs-12">
{{ page.content }}
</div>
{% endif %}
{% if page.sidebar_right %}
<div class="sidebar-right col-xs-2">
{{ page.sidebar_right }}
</div>
{% endif %}
</div>
{% if page.footer %}
<div class="row">
<div class="footer col-xs-12">
{{ page.footer }}
</div>
</div>
{% endif %}
</div>
Default regions
If you declare any regions in your theme, even just one, all the default regions will no longer be applied, and you assume responsibility for declaring any and all regions you want to use.
Questions
What is the default theme for Drupal 10?
The Olivero theme is the default theme for Drupal 9 and Drupal 10. It was introduced as part of the effort to modernize the look and feel of Drupal's core themes and to provide a more contemporary and user-friendly design.
What is the purpose of the Starterkit?
Generating a new theme. The Drupal Starterkit is a new theme generation tool introduced in Drupal 10, designed to streamline the process of creating custom themes. It serves as a foundational starting point for developers.
When creating a theme.info.yml file, which keys are always required?
- name
- type
- base theme
- core_version_requirement
Which file is used to define CSS and JS in a theme?
theme.libraries.yml ; By defining libraries, you can manage the loading of assets more efficiently. This helps in organizing your theme's resources and ensures that only the necessary files are loaded on a page, improving performance.