1. Introduction

Thymeleaf is a Java template engine for processing and creating HTML, XML, JavaScript, CSS and plain text. For an intro to Thymeleaf and Spring, have a look at this write-up.

In this write-up, we’ll focus on templating – something that most reasonably complex sites need to do one way or another. Simply put, pages need to share common page components like the header, footer, menu and potentially much more.

Thymeleaf addresses that with custom dialects – you can build layouts using the Thymeleaf Standard Layout System or the Layout Dialect – which uses the decorator pattern for working with the layout files.

In this article, we’ll discuss a handful of features of Thymeleaf Layout Dialect – which can be found here. To be more specific, we will discuss its features like creating layouts, custom titles or head element merging.

2. Maven Dependencies

First, let’s see the required configuration needed to integrate Thymeleaf with Spring. The thymeleaf-spring library is required in our dependencies:

Note that, for a Spring 4 project, the thymeleaf-spring4 library must be used instead of thymeleaf-spring5. The latest version of the dependencies may be found here.

We’ll also need a dependency for custom layouts dialect:

<dependency>
    <groupId>nz.net.ultraq.thymeleaf</groupId>
    <artifactId>thymeleaf-layout-dialect</artifactId>
    <version>2.4.1</version>
</dependency>

The latest version can be found at the Maven Central Repository.

3. Thymeleaf Layout Dialect Configuration

In this section, we will discuss how to configure Thymeleaf to use Layout Dialect. If you want to take a step back and see how to configure Thymeleaf 3.0 in your web app project, please check this tutorial.

Once we add Maven dependency as a part of a project, we’ll need to add the Layout Dialect to our existing Thymeleaf template engine. We can do this with Java configuration:

SpringTemplateEngine engine = new SpringTemplateEngine();
engine.addDialect(new LayoutDialect());

Or by using XML file config:

<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine">
    <property name="additionalDialects">
        <set>
            <bean class="nz.net.ultraq.thymeleaf.LayoutDialect"/>
        </set>
    </property>
</bean>

When decorating the sections of the content and layout templates, the default behaviour is to place all content elements after the layout ones.

Sometimes we need a smarter merging of elements, allowing to group similar elements together (js scripts together, stylesheets together etc.).

To achieve that, we need to add sorting strategy to our configuration – in our case, it will be the grouping strategy:

engine.addDialect(new LayoutDialect(new GroupingStrategy()));

or in XML:

<bean class="nz.net.ultraq.thymeleaf.LayoutDialect">
    <constructor-arg ref="groupingStrategy"/>
</bean>

The default strategy is to append elements. With above-mentioned, we will have everything sorted and grouped.

If neither strategy suits our needs, we can implement our own SortingStrategy and pass it along to the dialect like above.

4. Namespace and Attribute Processors’ Features

Once, configured we can start using layout namespace, and five new attribute processors: decorate, title-pattern, insert, replace, and fragment.

In order to create the layout template that we want to use for our HTML files, we created the following file, named template.html:

<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
...
</html>

As we can see, we changed the namespace from the standard xmlns:th=”http://www.thymeleaf.org” to xmlns:layout=”http://www.ultraq.net.nz/thymeleaf/layout”.

Now we can start working with attribute processors in our HTML files.

4.1. layout:fragment

In order to create custom sections in our layout or reusable templates that can be replaced by sections which share the same name, we use fragment attribute inside our template.html body:

<body>
    <header>
        <h1>New dialect example</h1>
    </header>
    <section layout:fragment="custom-content">
        <p>Your page content goes here</p>
    </section>
    <footer>
        <p>My custom footer</p>
        <p layout:fragment="custom-footer">Your custom footer here</p>
    </footer>
</body>

Notice that there are two sections that will be replaced by our custom HTML – content and footer.

It’s also important to write the default HTML that’s going to be used if any of the fragments will not be found.

4.2. layout:decorate

Next step that we need to make is to create an HTML file, that will be decorated by our layout:

<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
  layout:decorate="~{template.html}">
<head>
<title>Layout Dialect Example</title>
</head>
<body>
    <section layout:fragment="custom-content">
        <p>This is a custom content that you can provide</p>
    </section>
    <footer>
        <p layout:fragment="custom-footer">This is some footer content
          that you can change</p>
    </footer>
</body>
</html>

As it is shown in the 3rd line, we use layout:decorate and specify the decorator source. All fragments from the layout file that match fragments in a content file will be replaced by its custom implementation.

4.3. layout:title-pattern

Given that the Layout dialect automatically overrides the layout’s title with the one that is found in the content template, you might preserve parts of the title found in the layout.

For example, we can create breadcrumbs or retain the name of the website in the page title. The layout:title-pattern processor comes with help in such a case. All you need to specify in your layout file is:

<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Baeldung</title>

So the final result for the layout and content file presented in the previous paragraph will look like this:

<title>Baeldung - Layout Dialect Example</title>

4.4. layout:insert/layout:replace

The first processor, layout:insert, is similar to Thymeleaf’s original th:insert, but allows to pass the entire HTML fragments to the inserted template. It is very useful if you have some HTML that you want to reuse, but whose contents are too complex to determine or construct with context variables alone.

The second one, layout:replace, is similar to the first one, but with the behaviour of th:replace, which will actually substitute the host tag by the defined fragment’s code.

5. Conclusion

In this article, we described a few ways of implementing layouts in Thymeleaf.

Note that the examples use the Thymeleaf version 3.0; if you want to learn how to migrate your project, please follow this procedure.

The full implementation of this tutorial can be found in the GitHub project.

How to test? Our suggestion is to play with a browser first, then check the existing JUnit tests as well.

Remember, you can build layouts using above-mentioned Layout Dialect or you can easily create your own solution. Hopefully, this article gives you some more insights on the topic and you will find your preferred approach depending on your needs.