Component-based theming with Layout Builder

I have previously written about using Drupal’s definition files in component-based theming and how it is possible to have component-specific layout and asset library definition files. Now that Layout Builder is stable it is time to have a look at how it can be used with theme components.

Two schools

There are two main approaches to integrating independent theme components with Drupal. They could be described as the ‘Twig developer’ approach and the ‘site builder’ approach.

In the Twig developer approach integration is done entirely in Twig ‘presenter’ templates. A significant benefit of this straightforward approach is that no contrib modules are required (although Component Libraries is usually used). There is also no need for endless pointing and clicking in the admin UI, and dealing with related configuration. The downside is that in most cases this approach leaves the admin UI disconnected from the components. This means that a site builder not familiar with Twig or with no access to the Twig templates has no way of affecting the appearance of the integrated components.

In the site builder approach integration is done using the admin UI. Until now this has required sophisticated contrib modules like Display Suite and UI Patterns, with their own ecosystems of related modules. These are great modules, but ideally it should be possible to use just Drupal core for the site builder approach. With Layout Builder in core we are a huge leap closer to that goal.

Revisiting an old example

Back in January 2017 I wrote a blog post on how to use UI Patterns to integrate a simple Code component. I will now use the same component in an example of how to use Layout Builder for the same task.

Step 1: Create layout and asset library definitions

Starting from where we ended up in that old blog post, we need to provide information about the component’s variables and assets to Drupal in some other way than a .ui_patterns.yml file. This can now be easily done using Drupal core’s definition files.

Drupal core only supports theme (or module) specific definition files, but the Multiple Definition Files module can be used to add support for component-specific files. The results are identical in both approaches, so using Multiple Definition Files is completely optional.

Multiple Definition Files does add one useful feature though. Drupal places layout regions in content, so for example a code region would be accessed in Twig as content.code. To remove this Drupalism, Multiple Definition Files makes layout regions accessible in the Twig root context, so a code region is accessible in Twig as just code.

The definitions in this example are in component-specific files. If you want to use Multiple Definition Files, be sure to enable the module at this point.

The layout definition, shila-code.layouts.yml:

shila_code:
label: 'Code'
category: 'Shila'
template: source/_patterns/01-molecules/content/shila-code/shila-code
library: shila_theme/shila_code
regions:
language:
label: 'Language'
code:
label: 'Code'

and the library definition, shila-code.libraries.yml:

shila_code:
css:
theme:
source/_patterns/01-molecules/content/shila-code/prism.css: {}
js:
source/_patterns/01-molecules/content/shila-code/prism.js: {}

Note the library reference in shila-code.layouts.yml, linking the two definitions. Be sure to clear caches after adding the new definitions.

(As a side note, the UI Patterns From Layouts module makes it possible to use Drupal’s definition files with UI Patterns as well.)

Step 2: Enable Layout Builder

After enabling the Layout Builder module, Layout Builder has to be enabled for our Code paragraphs type’s display.

If you are moving away from a Display Suite layout, be sure to select - None - for the layout and save the settings before enabling Layout Builder. It seems that if you do not do this, Display Suite is still active and Layout Builder won’t work as expected.

Manage display

Step 3: Integrate the component using Layout builder

Clicking on the ‘Manage layout’ button takes us to Layout Builder. Display Suite and UI Patterns show a textual representation of a layout, but Layout Builder is different as it displays the layout visually.

Layout Builder

First we remove the default section, then we add a new section and choose the ‘Code’ layout for it.

Choose layout

As a reminder, this is what our extremely simple shila-code.html.twig template looks like:

<pre><code{% if language %} class="language-{{ language }}"{% endif %}>{{ code }}</code></pre>

Layout Builder’s visual representation will not be a problem in many cases. However, components often use variables for non-visual purposes or have layouts with overlapping regions. Our Code component is a good example, since language is used as a part of a CSS class name. Layout Builder does not expect layouts to be used in this way, and the result is a completely unusable UI.

Unusable UI

Oh no. What we need is a text based way to configure the layout. The good news is that due to accessibility reasons a textual version of the Layout Builder UI is already in the works. So, let’s apply the patch from that issue, clear the caches, and see what happens.

Layout overview link

A ‘Layout overview’ link has appeared! Let’s click on it.

Layout overview

This is looking good! We can now add the right paragraph fields to the respective regions in the Code layout and then click on the ‘Save layout’ button. Let’s have a look at a page that contains a Code paragraph.

Broken component

Something is obviously going wrong here. Let’s have a look at the HTML source.

HTML source code showing markup from Drupal’s block and field templates.
HTML source code showing markup from Drupal’s block and field templates.

Since we have placed fields in Layout Builder blocks, there is unwanted HTML from the block and field templates. What we really need is just the contents of the fields, nothing else. This can be an issue with many independent theme components, since they often do not expect extra markup to be provided.

Display Suite has a ‘Full Reset’ field formatter and UI Patterns has an ‘Only content’ option. But what can we do here? Creating specific Twig templates to remove the HTML is an option, but not an ideal one. What we want is an easy UI based way to deal with the problem.

Step 4: Install and enable the Full Reset module (if required)

After searching for existing solutions and not coming up with anything, I ended up writing a small module for this particular purpose. Full Reset does two things: it provides a field formatter and adds a reset option to Layout Builder blocks. The name is a hat tip to the trusty Display Suite field formatter I have used so many times.

A good way to support third party settings for Layout Builder blocks is still being worked on, so a core patch must be applied for Full Reset to work.

With the core patch applied and Full Reset installed and enabled, we can select the ‘Full Reset’ field formatter and tick the ‘Full Reset this block’ checkbox.

Full Reset options

Now the block and field templates are not used at all, and the component works and looks like expected! It still does not work in Layout Builder’s visual preview though, because Layout Builder expects the content to be a valid DOM node and have a surrounding HTML tag. For this reason Full Reset does not remove block theming in the preview.

Conclusion

Layout Builder can be successfully used in component-based theming today. There might be some problems with specific components like the one in this example, but these problems can be circumvented by applying two patches and using the Full Reset module.

For me this means that I can now stop using Display Suite, a module that I have used in almost all of my Drupal projects since 2011. Personally I find this change to be just as significant as it was when Field API and Views were added to core.

Comments

I have previously written about using Drupal’s definition files in component-based theming and how it is possible to have component-specific layout and asset library definition files. Now that Layout Builder is stable it is time to have a look at how it can be used with theme components.

Interactions

Reposted by Miguel Galán
Reposted by Alex Moreno
Reposted by salem_ghoweri
Reposted by Jacine Luisi
Reposted by Mark Conroy
Reposted by Bolt Design System
Reposted by Tamás Hajas