o7planning

Thymeleaf Fragments Tutorial with Examples

  1. What is Fragment?
  2. th:insert, th:replace, th:include
  3. Fragment with parameters
  4. th:assert

1. What is Fragment?

A Fragment is a part of a Template. Thymeleaf allows you to import fragments of this Template into another Template. There are many ways for you to identify a Fragment. For example:
  • Select all tags with attribute th: fragment = "search-fragment".
  • Select the tag by ID.
  • Select all tags by Css-class.
  • ....
The important thing when you want to import a Fragment of a Template is that you have to describe its position.
Th syntax for describing the position of a Fragment of a Template:
~{/path-to-template/template-name :: selector}
If you want to describe the position of Fragment of current Template, it is possible to use a shorter syntax:
~{:: selector}

~{this :: selector}
~{templatename: fragmentname} (th:fragment)
Select a fragment by name.
~{templatename: tagname} (Tag Name)
Choose a fragment by tag name:
Select the sub-tags of a tag. For example, select all <script> tags located in the <header> tag:
~{templatename: #id} (ID)
Select the fragment by the value of the ID attribute of tag.
~{templatename: .classname},~{templatename: tagname.classname} (Css Class)
Select fragment by Css Class:
~{templatename} (Everything)
Select all in Template:
Other...
Other examples:
~{fragments/my-template :: #tagId/text() }

~{fragments/my-template :: fragmentName/text() }

~{fragments/my-template :: tagName/text() }

2. th:insert, th:replace, th:include

The feature that allows importing fragments from one Template to another one is really great. It helps designing the website's interface become easier. Let's look at the following example:
In this example, my-template.html file contains many fragments, which other Templates can import for use.
/fragments/my-template.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>My Template</title>
    <link rel="stylesheet" type="text/css" th:href="@{/main.css}"/>
    <link rel="stylesheet" type="text/css" th:href="@{/secondary.css}"/>
    <script type="text/javascript" th:src="@{/main.js}"></script>
    <script type="text/javascript" th:src="@{/secondary.js}"></script>
</head>
<body>
    <!-- Script in body -->
    <script type="text/javascript" th:src="@{/script-in-body.js}"></script>
    <ul th:fragment="my-fragment1">
        <li><a th:href="@{/}">Home</a></li>
        <li><a th:href="@{/products}">Products</a></li>
        <li><a th:href="@{/about}">About</a></li>
    </ul>
    <ul th:fragment="my-fragment2">
        <li><a th:href="@{/admin/products}">Product Management</a></li>
        <li><a th:href="@{/admin/orders}">Order Management</a></li>
    </ul>
    <div id = "my-id1">
         Element DIV with id = 'my-id1'
    </div>
    <aside>
        <div>This is a sidebar</div>
    </aside>
    <p class="my-class">Element P with class (my-class)</p>
    <p>Element P without class</p>
    <p class="my-class">Element P with class (my-class)</p>
</body>
</html>
The my-page.html file is a Template. It imports some fragments of my-template.html:
my-page.html (Template)
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title th:replace = "~{fragments/my-template :: title}">Title</title>
<th:block th:insert="~{fragments/my-template :: link}"></th:block>
<th:block th:insert="~{fragments/my-template :: head/script}"></th:block>
</head>
<body>
   <h1>My Page</h1>
   <p>Some Content of My Page</p>
   <div th:insert="~{fragments/my-template :: my-fragment1}"></div>
   <div th:insert="~{fragments/my-template :: my-fragment2}"></div>
   <div th:insert="~{fragments/my-template :: #my-id1}"></div>
   <div th:insert="~{fragments/my-template :: p.my-class }"></div>
</body>
</html>
The result which you receive:
(HTML Result)
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8" />
    <title>My Template</title>
    <link rel="stylesheet" type="text/css" href="/main.css" />
    <link rel="stylesheet" type="text/css" href="/secondary.css" />
    <script type="text/javascript" src="/main.js"></script>
    <script type="text/javascript" src="/secondary.js"></script>
</head>
<body>
    <h1>My Page</h1>
    <p>Some Content of My Page</p>
    <div>
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/products">Products</a></li>
            <li><a href="/about">About</a></li>
        </ul>
    </div>
    <div>
        <ul>
            <li><a href="/admin/products">Product Management</a></li>
            <li><a href="/admin/orders">Order Management</a></li>
        </ul>
    </div>
    <div>
        <div id="my-id1">
            Element DIV with id = 'my-id1'
        </div>
    </div>
    <div>
        <p class="my-class">Element P with class (my-class)</p>
        <p class="my-class">Element P with class (my-class)</p>
    </div>
</body>
</html>
th:insert, th:replace, th:include
  • th:insert will insert Fragment to act as the child of Target tag.
  • th:replace will replace target tag with Fragment.
  • th:include will insert the child of Fragment to act as the child of Target tag.
Note: The th:include attribute is used in Thymeleaf 2, and no longer used in the Thymeleaf 3 version.
/path/mytemplate.html (Fragments)
<footer th:fragment="copyright">
  &copy; o7planning.org
</footer>
Target Template:
(Target Template)
<body>
  ...
  <!-- th:insert -->
  <div th:insert="~{/path/mytemplate :: copyright}"></div>
  <!-- th:replace -->
  <div th:replace="~{/path/mytemplate :: copyright}"></div>
  <!-- th:include -->
  <div th:include ="~{/path/mytemplate :: copyright}"></div>
</body>
Result:
(HTML Result)
<body>
  ...
  <!-- th:insert -->
  <div>
    <footer>
      &copy; o7planning.org
    </footer>
  </div>
  <!-- th:replace -->
  <footer>
    &copy; o7planning.org
  </footer>
  <!-- th:include -->
  <div>
    &copy; o7planning.org
  </div>
</body>

3. Fragment with parameters

A fragment will be like a function if it add parameters and luckily, the Thymeleaf supports this.
Explicit parameters:
If you declare a fragment and enumerate explicitly its list of parameters. These parameters will be compulsory parameters such as the following example:
<div th:fragment="person (firstName, lastName)" class="box">
    <p>First Name: <span th:utext="${firstName}"></span></p>
    <p>Last Name: <span th:utext="${lastName}"></span></p>
    <p>Full Name: <span th:utext="${firstName} + ' '+ ${lastName}"></span></p>
</div>
Truyền tham số khi bạn gọi fragment:
<div th:replace="~{fragments/my-template2 :: person('Donald', 'Trump') }"></div>
    
<div th:replace="~{fragments/my-template2 :: person( firstName='Donald', lastName= 'Trump') }"></div>

<div th:replace="~{fragments/my-template2 :: person( ${u.firstName}, ${u.lastName}) }"></div>

<div th:replace="~{fragments/my-template2 :: person( firstName=${u.firstName}, lastName= ${u.lastName}) }"></div>
Implicitparameters
You can create a fragment with implicit parameters. They are optional parameters, such as the following example:
<!-- Fragment with implicit parameters. -->
<div th:fragment="greeting" class="box">
    <p>Hello
       <span th:utext="${title}"></span>
       <span th:utext="${name} ?: 'There'"></span>
    </p>
</div>
Call fragment which has implicit parameters.
<div th:replace="~{fragments/my-template2 :: greeting(title='Mr.', name = 'Tom') }"></div>    
    
<div th:replace="~{fragments/my-template2 :: greeting }"></div>

4. th:assert

th:assert attribute helps you evaluate an expression, or multiple expressions (Expressions separated by commas). If all expressions are evaluated to be true, there will be no problem, if an expression is evaluated as false an exception will be thrown.
<div th:fragment="employee (firstName, lastName)" class="box"
     th:assert= "${!#strings.isEmpty(firstName)}, ${!#strings.isEmpty(lastName)}">
    
    <p>First Name: <span th:utext="${firstName}"></span></p>
    <p>Last Name: <span th:utext="${lastName}"></span></p>
    <p>Full Name: <span th:utext="${firstName} + ' '+ ${lastName}"></span></p>
</div>