A fragment in Thymeleaf is a small piece of code that can be included in other templates. It is a common practice in web development to create reusable, small components like the header, footer, navigation menu and other parts of a website that are repeated used on multiple pages.
In this article, you'll learn how to create and use fragments in Thymeleaf templates. If you are new to Thymeleaf, take a look at the introductory tutorial to learn how to use Thymeleaf with Spring Boot.
Note: For more complex Thymeleaf layouts and reusable templates, take a look at Thymeleaf Layout Dialect tutorial.
Defining & Referencing Fragments
To define a Thymeleaf fragment, you need to use the th:fragment
attribute. You can define fragments either in separate files (recommended) or in a common file. It is also a good practice to place all fragments in a dedicated folder called fragments
inside the templates directory (src/main/resources/templates/
).
Let us say you want to define a reusable footer component to add copyright information to all of your web pages, so you just create a footer.html
file with the following content:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<footer th:fragment="footer">
<p>© 2020 attacomsian.com</p>
</footer>
</body>
</html>
The above code defined a fragment called footer
that you can easily include to your homepage by using one of the th:insert
or th:replace
attributes:
<body>
...
<div th:insert="fragments/footer :: footer"></div>
</body>
You can also define more than one fragment in a single HTML document as shown in the blow file called components.html
:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<header th:fragment="header">
<h1>Welcome to My Blog</h1>
</header>
<nav th:fragment="menu">
<a th:href="@{/}">Homepage</a>
<a th:href="@{/about}">About Me</a>
<a th:href="@{/blog}">Blog</a>
<a th:href="@{/contact}">Contact</a>
</nav>
<footer th:fragment="footer">
<p>© 2020 attacomsian.com</p>
</footer>
</body>
</html>
th:insert
& th:replace
Attributes
Thymeleaf provides multiple ways to include a fragment into a template:
th:insert
— Inserts the fragment content inside the host tagth:replace
&mdahs; Replaces the host tag with the specified fragment contentth:include
— Similar toth:insert
but it only inserts the contents of the specified fragment (depreciated since 3.0)
The following example shows how you can include the header
fragment from components.html
using the above three approaches:
<body>
<div th:insert="fragments/components :: header"></div>
<div th:replace="fragments/components :: header"></div>
<div th:include="fragments/components :: header"></div>
</body>
The rendered HTML document will look like the following:
<body>
<div>
<header>
<h1>Welcome to My Blog</h1>
</header>
</div>
<header>
<h1>Welcome to My Blog</h1>
</header>
<div>
<h1>Welcome to My Blog</h1>
</div>
</body>
Including with DOM Selectors
In Thymeleaf, you don't need to explicitly use th:fragment
attribute to define fragments. They can be included in another template by using just DOM selectors like class name, element ID, or tag name similar to do what we do in JavaScript.
Here is an example:
<div th:insert="fragments/components :: div.title"></div>
The above example will include a <div>
element that has the .title
CSS class from the compoments.html
file.
Parametrized Fragments
Thymeleaf fragments defined with th:fragment
attribute can specify arguments, just like methods. To use a parameterized fragment, you need to define it as a function call with a declared list of parameters:
<div th:fragment="name(firstName, lastName)">
<p>
Hey! I'm <span th:text="${firstName + ' ' + lastName}"></span>!
</p>
</div>
Now you can use one of the following syntaxes to include the above fragment using th:replace
or th:insert
attribute:
<!--Option 1-->
<div th:replace="fragments/components :: name('John', 'Doe')"></div>
<!--Option 2-->
<div th:replace="fragments/components :: name(firstName='John', lastName='Doe')"></div>
Since the second option uses named parameters, the order of the parameters is no longer important:
<div th:replace="fragments/components :: name(lastName='Doe', firstName='John')"></div>
Thymeleaf parameterized fragments are very useful as it allows us to reuse one small piece of code in many different ways.
Fragment Inclusion Expressions
Thymeleaf fragment inclusion syntax fully supports conditional expressions to dynamically load different fragments. In templatename :: selector
format, both templatename
and selector
can be fully-featured expressions.
For example, in the below code snippet, we want to include different fragments depending on a condition. If the authenticated user is an administrator, we will show a different footer; otherwise, the default one:
<div th:replace="fragments/footer :: ${user.admin} ? 'footer-admin' : 'footer'"></div>
The footer.html
file looks slightly different, as we have to define two footers now:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<!--Default Footer-->
<footer th:fragment="footer">
<p>© 2020 Default Footer</p>
</footer>
<!--Admin Footer-->
<footer th:fragment="admin-footer">
<p>© 2020 Admin Footer</p>
</footer>
</body>
</html>
If the fragments, you want to conditionally include, are defined in separate files, you have to use the fragment expression syntax introduced in version 3.0:
<div th:replace="${user.admin} ? ~{fragments/footer :: footer} :
~{fragments/components :: footer}"></div>
Flexible Layouts
Fragment expressions are useful not only for defining fragments that use numbers, strings, bean objects as parameters, but also fragments of markup. This allows us to create fragments that can be enhanced with the markup coming from the calling templates, thus providing a very flexible layout technique.
Let us say that you want to create a base <head>
section with a default list of styles and scripts, but also want to have a possibility to extend the list with other resources if required.
Here is how the base header looks like:
base.html
<head th:fragment="baseHead(title, links)">
<title th:replace="${title}">Atta | Founder. Developer. Blogger.</title>
<!-- default styles and scripts -->
<link rel="shortcut icon" th:href="@{/images/favicon.ico}">
<link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
<script th:src="@{/js/jquery.min.js}"></script>
<!-- placeholder for additional links -->
<th:block th:replace="${links}" />
</head>
Now if you want to include additional links to the default header, just call the baseHead
fragment like below in your template:
<head th:replace="fragments/base :: baseHead(~{::title}, ~{::link})">
<title>Introduction to Thymeleaf Fragments | Atta Blog</title>
<link rel="stylesheet" th:href="@{/css/font-awesome.min.css}">
<link rel="stylesheet" th:href="@{/css/jquery-ui.css}">
</head>
In the above example, ::tittle
and ::link
are pointing to the title and link tags in the calling template. The resultant header will use the actual <title>
and <link>
tags from the calling template as the values of the title
and links
parameters as shown in the below-rendered HTML:
<head>
<title>Introduction to Thymeleaf Fragments | Atta Blog</title>
<!-- default styles and scripts -->
<link rel="shortcut icon" href="/images/favicon.ico">
<link rel="stylesheet" href="/css/bootstrap.min.css">
<script src="/js/jquery.min.js"></script>
<!-- placeholder for additional links -->
<link rel="stylesheet" href="/css/font-awesome.min.css">
<link rel="stylesheet" href="/css/jquery-ui.css">
</head>
Layout Inheritance
Thymeleaf fragments can also be used to create a simple layout. For example, you can create a single file called layout.html
that has the following structure:
layout.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" th:fragment="layout(title, content)">
<head>
<meta charset="UTF-8">
<title th:replace="${title}">Layout Title</title>
</head>
<body>
<h1>Layout Main Heading</h1>
<section th:replace="${content}">
<p>Layout contents</p>
</section>
<footer>
<p>© 2020 Layout footer</p>
</footer>
</body>
</html>
As you can see above, we have declared a fragment called layout
with title
and content
as parameters. Both these parameters will be replaced with the calling template tags by using the fragment expressions as shown below:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
th:replace="layout :: layout(~{::title}, ~{::section})">
<head>
<title>Welcome to My Site</title>
</head>
<body>
<section>
<p>This is just an extra text.</p>
<a th:href="@{/contact-us}">Contact Us</a>
</section>
</body>
</html>
In rendered HTML document, the <html>
tag will be replaced by the layout
fragment. But in the layout
fragment, title
and content
will be replaced by <title>
and <section>
blocks respectively.
Here is the final HTML output:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Welcome to My Site</title>
</head>
<body>
<h1>Layout Main Heading</h1>
<section>
<p>This is just an extra text.</p>
<a href="/contact-us">Contact Us</a>
</section>
<footer>
<p>© 2020 Layout footer</p>
</footer>
</body>
</html>
Conclusion
That's all folks. In this article, we looked at how to create and reuse different components of a web page with the help of Thymeleaf fragments, a powerful feature that makes the template management easier and flexible.
We also discussed different formats available to include fragments in Thymeleaf templates, and how to work with parameterized fragments. In the end, we presented an example to create simple layouts using fragment expression syntax.
To learn more about Thymeleaf layouts, take a look at the official documentation that presents more in-depth examples.
Read Next: Working with Thymeleaf Layout Dialect in Spring Boot
✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.