Thymeleaf is a modern server-side template engine for Java-based web and standalone environments. It can process any HTML, XML, CSS, JavaScript, or plain-text file and provides Spring Framework integration.

In my previous article, I have explained how to use Thymeleaf fragments to create small, reusable components like the header, footer, menu, etc. and include them to other templates. While fragments are good enough for working with small applications, they become hard to maintain and update as the application grows to hundreds of views.

In this article, we'll look at another way of sharing common page components like headers, footers, menus, and more by using Thymeleaf Layout Dialect. It is an open-source dialect for Thymeleaf that lets you easily build complex layouts and reusable templates to achieve higher code reusability in Spring Boot applications.

Dependencies

Apart from Thymeleaf and Spring Boot Web starter dependencies, you also need to include thymeleaf-layout-dialect dependency for Thymeleaf Layout Dialect support.

For Gradle, include the following three dependencies to your build.gradle file:

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'

For Maven, make sure you have included the following dependencies to pom.xml file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>nz.net.ultraq.thymeleaf</groupId>
    <artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>

If you want to create a new Spring Boot project from scratch, just use Spring Initializr web tool or Spring Boot CLI.

That's all you need to do. Spring Boot will automatically configures the Thymeleaf Layout Dialect for you.

Namespace and Attribute Processors

Thymeleaf Layout Dialect will introduce the layout namespace along with 5 new attribute processors that you can use in your templates: decorate, title-pattern, insert, replace, and fragment.

To use Layout Dialect attributes in a template, you need to add the layout namespace to the <html> tag as shown below:

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

layout:fragment Attribute

The layout:fragment attribute marks sections in your layout or reusable templates that can be replaced by sections with the same name in content templates. Here is an example:

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

    <div layout:fragment="content">
        <p>Body contents</p>
    </div>

</body>
</html>

As you can see above, we have defined a section using layout:fragment that can be replaced by the content template. If no fragment with a similar name is found in content templates, the default HTML contents will be shown.

Note: Fragment names must be unique within a template, otherwise fragment mismatches will occur and an exception will be thrown.

layout:decorate Attribute

The layout:decorate is an important attribute processor that is used in content templates. It is declared in the root tag (usually <html> in HTML document) as a fragment expression to specify the layout template to decorate the current content template.

Here is an example that shows how you can decorate the content template:

<!DOCTYPE html>
<html lang="en" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout}">
<body>

    <div layout:fragment="content">
        <p>Welcome to Thymeleaf Layout Dialect</p>
    </div>

</body>
</html>

In the above example on the 3rd line, we used the layout:decorate attribute to specify the layout template as a decorate source. We also defined a fragment that will replace the one we have declared in the layout template.

layout:title-pattern Attribute

By default, Thymeleaf Layout Dialect automatically replaces the layout template title with the one that is found in the content template. But you may want to keep a part of the layout template's title.

That's where the layout:title-pattern attribute comes into the play. It allows us to specify a pattern with some special tokens to control the resulting <title> element. So instead of overriding the layout template title, you can actually extend it with apart from the content template.

The following example shows how you can extend the layout's title by using the layout:title-pattern attribute:

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

The above <title> tag must be defined in the layout template. Both $CONTENT_TITLE and $LAYOUT_TITLE are special keywords that represent the content template and layout template titles respectively.

Now if you define the following <title> tag in the content template:

<title>Understanding Thymeleaf Layout Dialect</title>

The resulting <title> tag rendered in the HTML document will look like the following:

<title>Understanding Thymeleaf Layout Dialect - Atta Blog</title>

layout:insert & layout:replace Attributes

The layout:insert attribute is very much similar to Thymeleaf's th:insert, but allows us to pass the entire element fragments to the inserted templates. It is quite helpful if you want to reuse an HTML component whose contents are too complex to be constructed by the context variables alone.

The layout:replace attribute is similar to the first one, but with the behavior of th:replace; replaces the host tag with the content of the fragment.

Layout Dialect Example

Enough of the talk, let us do some practical work now to see how Thymeleaf Layout Dialect actually works in a real-world application.

Layout Template

Let us first create a layout template called layout.html and place it into the src/main/resources/templates/ directory. This template will contain a layout that will be shared among other templates.

layout.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title layout:title-pattern="$CONTENT_TITLE - $LAYOUT_TITLE"></title>

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
</head>
<body>

<!-- Main Navigation -->
<nav class="navbar navbar-expand-md navbar-dark bg-primary">
    <a class="navbar-brand" th:href="@{/}">Business Name</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="navbar"
            aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" id="navbar">
        <ul class="navbar-nav ml-auto">
            <li class="nav-item active">
                <a class="nav-link" th:href="@{/}">Home</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" th:href="@{/contact}">Contact Us</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" th:href="@{/about}">About Us</a>
            </li>
        </ul>
    </div>
</nav>

<!-- Content Section -->
<section layout:fragment="content">
    <p>This is filled by the content template.</p>
</section>

<!-- Footer -->
<footer class="container py-5">
    <div class="row">
        <div class="col-md-12">
            <p class="text-muted">&copy; 2020 Business Name. All rights reserved.</p>
        </div>
    </div>
</footer>

<!-- Optional Section -->
<th:block layout:fragment="optional" />

</body>
</html>

As you can see above, we have declared our shared components such as the header, footer, navigation, and the main content section all in one place in our layout template. If you have read the fragment tutorial, you can quickly spot the difference. We no longer need to create multiple fragments for different shared components. This is the biggest advantage of using Thymeleaf Layout Dialect.

Also notice the layout:fragment attribute we applied to the <section> tag and to the <th:block> element processor provided by the Thymeleaf. These are the sections in the layout that are eligible for replacement by matching fragments in content templates.

Content Templates

The next step is to create some content templates for homepage, contact, and about us pages:

index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout}">
<head>
    <title>Welcome to Our Site</title>
</head>
<body>

<div layout:fragment="content">
    <section class="my-5">
        <div class="container">
            <div class="row">
                <div class="col-md-12">
                    <h1>Welcome to Our Site</h1>
                    <p>Lorem ipsum dolor sit amet, consectetur [....]</p>
                </div>
            </div>
        </div>
    </section>
</div>

</body>
</html>

contact.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout}">
<head>
    <title>Contact Us</title>
</head>
<body>

<div layout:fragment="content">
    <section class="my-5">
        <div class="container">
            <div class="row">
                <div class="col-md-12">
                    <h1>Contact Us</h1>
                    <p>Please send us an email at help@example.com.</p>
                </div>
            </div>
        </div>
    </section>
</div>

<th:block th:fragment="optional">
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
</th:block>

</body>
</html>

about.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      layout:decorate="~{layout}">
<head>
    <title>About Us</title>
</head>
<body>

<div layout:fragment="content">
    <section class="my-5">
        <div class="container">
            <div class="row">
                <div class="col-md-12">
                    <h1>About Us</h1>
                    <p>Lorem ipsum dolor sit amet, [...]</p>
                </div>
            </div>
        </div>
    </section>
</div>

</body>
</html>

There is nothing new in the above content templates. We just used layout:decorate attribute in the <html> tag to specify the name of the layout template that should be decorated using these content templates.

The content templates override the fragment sections to define their own contents along with titles. In the contact.html template, we have also overridden the optional layout fragment to load the jQuery file.

Spring Boot Controller

Finally, let us create a simple Spring Boot web controller that handles the GET HTTP requests on /, /contact, and /about end-points as shown in the below example:

IndexController.java

@Controller
public class IndexController {

    @GetMapping("/")
    public String homePage() {
        return "index";
    }

    @GetMapping("/contact")
    public String contactPage() {
        return "contact";
    }

    @GetMapping("/about")
    public String aboutPage() {
        return "about";
    }
}

Running & Testing the Application

To launch the Spring Boot application, we need to first add the main application class:

Application.java

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
    
}

Now run the following command in your terminal from the root directory of the project to start the application:

$ ./gradlew bootRun

If you use Maven, execute the following command:

./mvnw spring-boot:run

Once the application is started, open http://localhost:8080/ in a web browser to view the home page. Here is how it looks like:

Spring Boot Thymeleaf Layout Exaple

Source Code: Download the complete source code from GitHub available under MIT license.

Conclusion

That's all folks! In this article, you have learned how to use Thymeleaf Layout Dialect in a Spring Boot web application to build highly customizable layouts and reusable templates to improve code reusability.

All you need to do is just include the required dependencies to your project to use the Layout Dialect features. Spring Boot auto-configuration support will configure all the required beans for you.

Thymeleaf Layout Dialect introduces a new layout namespace, and 5 new attribute processors that you can use in your templates: decorate, fragment, insert, replace, and title-pattern.

To learn more about Thymeleaf Layout Dialect, take a look at the official documentation.

✌️ Like this article? Follow @attacomsian on Twitter. You can also follow me on LinkedIn and DEV. Subscribe to RSS Feed.

👋 If you enjoy reading my articles and want to support me to continue creating free tutorials, Buy me a coffee (cost $3) .

Need help to launch a new product? I am available for contract work. Hire me to accomplish your business goals with engineering and design.