How to work with Fragments in Thymeleaf

January 04, 2020 No comments Fragment Thymeleaf Spring

1. Introduction

In this article, we will show how to use Fragments in Thymeleaf templates. Fragment representing a piece of a template that can be included in other templates. It could be a header, menu, footer and any other part of a document usually repeated on many pages. Fragments can be parametrized and included with specific initial parameters.

If you need more information about how to install and use Thymeleaf in Spring Boot application follow that link: Spring Boot with Thymeleaf.

2. Including template fragments

To define new Thymeleaf Fragment we are using th:fragment attribute. Fragments could be isolated in a separate file (and we recommend this approach) or defined in any other template.

The simplest Fragment could have the following structure:

<footer th:fragment="footer">
    <p>2019 FrontBackend.com</p>
</footer>

We can also define more than one Fragment in a single HTML document that could be also a well-formed HTML file:

<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Spring Boot Thymeleaf Application - Fragments</title>
</head>
<body>

<div th:fragment="header">
    <h1>Thymeleaf Fragments</h1>
</div>

<div th:fragment="menu">
    <a href="#home" class="active">Home</a>
    <a href="#blog">Blog</a>
    <a href="#contact">Contact</a>
    <a href="#about">About</a>
</div>

<footer th:fragment="footer">
    <p>2019 FrontBackend.com</p>
</footer>

</body>
</html>

There are three ways to include content from fragments:

  • using th:insert attribute - inserts the specified fragment inside the host tag,
  • using th:replace attribute - replaces a whole host tag with the specified fragment,
  • using th:include attribute - similar to th:insert but it inserts only the content of specified fragment (deprecated).

In the following example, we include footer fragment from parts using three approaches:

<body>

  <div th:insert="parts :: footer"></div>

  <div th:replace="parts :: footer"></div>

  <div th:include="parts :: footer"></div>

</body>

The result page will have the following structure:

<body>

  <div>
    <footer>
      <p>2019 FrontBackend.com</p>
    </footer>
  </div>

  <footer>
    <p>2019 FrontBackend.com</p>
  </footer>

  <div>
    <p>2019 FrontBackend.com</p>
  </div>

</body>

3. Selectors for Fragments

Thymeleaf fragments can be included into another template using simple DOM selectors. We can grab HTML elements using their id or a class name. In the following example we include four fragments, one div.panel using class name of the DIV element:

<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Spring Boot Thymeleaf Application - Fragments Main</title>
</head>
<body>

<header th:insert="_parts :: header"> </header>
<div th:replace="_parts :: menu"></div>
<div th:replace="_parts :: div.panel"></div>
<div th:replace="_parts :: footer"></div>

</body>
</html>

The result will have the following structure:


<!DOCTYPE HTML>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Spring Boot Thymeleaf Application - Fragments Main</title>
</head>
<body>

<header>
<div>
    <h1>Thymeleaf Fragments</h1>
</div>
</header>
<div>
    <a href="#home" class="active">Home</a>
    <a href="#blog">Blog</a>
    <a href="#contact">Contact</a>
    <a href="#about">About</a>
</div>
<div class="panel">
    This is a sample panel
</div>
<footer>
    <p>2019 FrontBackend.com</p>
</footer>

</body>
</html>

3. Parametrized Fragments

Fragments defined with th:fragment can specify a set of input parameters. To use parametrized fragments we need to provide a fragment name with declared list of parameters.

<div th:fragment="fragmentName(parameter1, parameter2 ...)">
    ...
</div>

In the following example, we define a fragment responsible for presenting a single contact row in an HTML table.

<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Spring Boot Thymeleaf Application - Fragments Tables</title>
</head>
<body>

<table>
    <tr th:fragment="contactRow(stat, row)">
        <td th:text="${stat.count}">1</td>
        <td th:text="${row.name}">Name</td>
        <td th:text="${row.email}">Email</td>
        <td th:text="${row.type.name() == 'INDIVIDUAL' ? 'Individual' : 'Group'}"></td>
        <td>
            <th:block th:if="${row.type.name() == 'GROUP'}">
                <p th:each="member : ${row.members}" th:text="${member.email}"></p>
            </th:block>
        </td>
    </tr>
</table>

</body>
</html>

We use th:replace attribute to include a parametrized fragment contactRow(stat, row) with our contact list:

<!DOCTYPE HTML>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Spring Boot Thymeleaf Application - Fragments - Contacts</title>
</head>
<body>

<table cellspacing="1" cellpadding="1" border="1">
    <thead>
    <tr>
        <th>No</th>
        <th>Name</th>
        <th>Email</th>
        <th>Type</th>
        <th>Members</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="contact, stat : ${contacts}">
        <th:block th:replace="_tables :: contactRow(${stat}, ${contact})">row</th:block>
    </tr>
    </tbody>
</table>

</body>
</html>

Parametrized fragments give us a lot of possibilities. It allows us to reuse one piece of template in many different ways. We can also separate commonly used logic into one fragment and attach it in many templates.

4. Flexible layouts

Fragment expressions can be used not only for parameters like objects, numbers, lists, etc., we can also provide fragments of markup.

Let's say we want to have a defined set of stylesheets and javascript in a header section but also have a possibility to extend that list with other resources.

The base header fragment will have the following structure:

<head th:fragment="baseHeader(title,links)">

  <title th:replace="${title}">Base Title | FrontBackend</title>

  <!-- Common styles and scripts -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"/>
  <link rel="shortcut icon" th:href="@{/images/favicon.ico}">
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.slim.js"></script>

  <!--/* This is a laceholder for additional links */-->
  <th:block th:replace="${links}" />

</head>

And now if we want to put some additional links into our header simply use baseHeader like in the following example:

<head th:replace="base :: baseHeader(~{::title},~{::link})">

  <title>The best tutorial ever | FrontBackend</title>

  <link rel="stylesheet" th:href="@{/css/awesome.min.css}">
  <link rel="stylesheet" th:href="@{/jquery/jquery-ui.css}">

</head>

::title and ::link is pointing to a title and link elements in the current template. The result head tag will look like the following:

<head>

  <title>The best tutorial ever | FrontBackend</title>

  <!-- Common styles and scripts -->
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"/>
  <link rel="shortcut icon" th:href="@{/images/favicon.ico}">
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.slim.js"></script>

  <link rel="stylesheet" th:href="@{/css/awesome.min.css}">
  <link rel="stylesheet" th:href="@{/jquery/jquery-ui.css}">

</head>

5. Conclusion

In this article, we have shown how flexible a template layout mechanism in Thymeleaf is. We presented how to reuse fragments and how to work with parameterized templates. All the features make fragments an advanced tool for template management.

{{ message }}

{{ 'Comments are closed.' | trans }}