Creating Reusable Components using Fragments in Thymeleaf

Thymeleaf’s fragment feature empowers developers to build modular and reusable components within their web pages, enhancing code organization and maintainability. These fragments act as templates for specific sections of a web page, making it easier to create consistent and efficient layouts. In this article, we’ll explore how to use fragments in Thymeleaf to create reusable components.

How to use Fragments in Thymeleaf - Spring Boot

What are Fragments?

Fragments in Thymeleaf allow you to define sections of your HTML that can be reused across multiple templates. Instead of duplicating code for common sections like headers, footers, or navigation bars, you can encapsulate these parts as fragments and include them wherever needed.

Setting Up the Project

Before diving into fragments, let’s set up a simple Spring Boot project:

  1. Create a Spring Boot Project: Set up a new Spring Boot project using Spring Initializr.
  2. Dependency Configuration: Make sure you have the spring-boot-starter-thymeleaf dependency in your pom.xml or build.gradle file.

You can check our Blog on Thymeleaf and Bootstrap 5 Template Engine in Spring Boot with Example

1. Creating Fragments

Assume we want to create a reusable header and footer for our web pages. Here’s how you can set it up:

  • Header Fragment (header.html):

Create a new Thymeleaf fragment file named header.html within your src/main/resources/templates/fragments directory. This fragment defines the header section of your web page.

<!-- src/main/resources/templates/fragments/header.html -->

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <!-- Common header elements -->
</head>
<body>
    <header>
        <h1>My Awesome Website</h1>
        <!-- Navigation links -->
    </header>
  • Footer Fragment (footer.html):

Similarly, create a footer.html fragment within the same fragments directory. This fragment defines the footer section of your web page.

<!-- src/main/resources/templates/fragments/footer.html -->

    <footer>
        <p>&copy; 2023 My Awesome Website. All rights reserved.</p>
    </footer>
</body>
</html>

2. Using Fragments in Templates

Now that you’ve created your fragments, you can use them in your main templates. Here’s an example of a page template that includes the header and footer fragments:

<!-- src/main/resources/templates/page.html -->

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>My Page</title>
</head>
<body>
    <!-- Include the header fragment -->
    <div th:replace="fragments/header :: header"></div>

    <main>
        <!-- Content specific to this page -->
    </main>

    <!-- Include the footer fragment -->
    <div th:replace="fragments/footer :: footer"></div>
</body>
</html>

In the above template, the th:replace attribute is used to include the header and footer fragments into the page.

Exploring Thymeleaf Includes: A Variety of Approaches

Thymeleaf provides several mechanisms for including reusable components within your web pages. These approaches, including th:replace, th:insert, th:include, and th:fragment, allow you to create modular and maintainable templates. Let’s delve into each of these methods with practical examples.

1. Using th:replace

The th:replace attribute replaces the content of an element with the content of another template. It’s ideal for creating distinct sections that can be easily swapped out.

Consider a header fragment (header.html):

<!-- header.html -->

<header>
    <h1>Welcome to our Website</h1>
</header>

Include the header fragment in a page template (page.html):

<!-- page.html -->

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>My Page</title>
</head>
<body>
    <div th:replace="fragments/header :: header"></div>
    <main>
        <!-- Page-specific content -->
    </main>
</body>
</html>

2. Using th:insert

With th:insert, you can include content from another template within an element, but the surrounding elements are retained.

Consider a menu fragment (menu.html):

<!-- menu.html -->

<nav>
    <ul>
        <li><a href="#">Home</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Services</a></li>
    </ul>
</nav>

Include the menu fragment using th:insert in the page template:

<!-- page.html -->

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>My Page</title>
</head>
<body>
    <div th:insert="fragments/menu :: #menu"></div>
    <main>
        <!-- Page-specific content -->
    </main>
</body>
</html>

3. Using th:include

Unlike th:insert, th:include retains both the included content and its surrounding elements.

Consider a sidebar fragment (sidebar.html):

<!-- sidebar.html -->

<aside>
    <h3>Recent Posts</h3>
    <ul>
        <li>Post 1</li>
        <li>Post 2</li>
        <li>Post 3</li>
    </ul>
</aside>

Include the sidebar fragment using th:include in the page template:

<!-- page.html -->

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>My Page</title>
</head>
<body>
    <main>
        <!-- Page-specific content -->
    </main>
    <div th:include="fragments/sidebar :: sidebar"></div>
</body>
</html>

4. Using th:fragment

The th:fragment attribute defines a named fragment that can be included using th:insert or th:replace.

In a reusable fragment (fragment.html):

<!-- fragment.html -->

<div th:fragment="info-box">
    <div class="info-box">
        <p>This is an informative message.</p>
    </div>
</div>

Include the named fragment in a page template:

<!-- page.html -->

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>My Page</title>
</head>
<body>
    <div th:insert="fragments/fragment :: info-box"></div>
    <main>
        <!-- Page-specific content -->
    </main>
</body>
</html>

List of commonly used th: attributes and methods in Thymeleaf

  1. th:text: Sets the inner text of an HTML element to the specified value or expression.
  2. th:if: Conditionally renders the content of an element based on the provided condition.
  3. th:unless: Conditionally renders the content of an element if the provided condition is false.
  4. th:switch: Declares a switch expression and contains multiple th:case elements to choose from based on the switch value.
  5. th:case: Defines a case block within a th:switch element, which is rendered if its value matches the switch value.
  6. th:each: Iterates over a collection and renders the contained elements for each item in the collection.
  7. th:object: Specifies the object to be used as a context for data binding within a form.
  8. th:href: Sets the value of the href attribute for anchor (<a>) elements.
  9. th:src: Sets the value of the src attribute for image (<img>) elements.
  10. th:attr: Sets one or more attributes of an HTML element based on the provided expressions.
  11. th:style: Sets the value of the style attribute for an HTML element.
  12. th:class: Sets the value of the class attribute for an HTML element, allowing dynamic class names.
  13. th:value: Sets the value attribute for input fields, such as text inputs, checkboxes, and radio buttons.
  14. th:selected: Conditionally marks an option as selected in a dropdown (<select>) element.
  15. th:fragment: Defines a named fragment within a template, which can be included using th:insert or th:replace.
  16. th:replace: Replaces the content of an HTML element with the content of another template or fragment.
  17. th:insert: Inserts the content of another template or fragment within an HTML element.
  18. th:include: Includes the content of another template or fragment while retaining the surrounding elements.
  19. th:block: Provides a container for conditional rendering, useful for wrapping a block of content that might or might not be rendered.
  20. th:text: Sets the text content of an HTML element.

These th: attributes and methods are fundamental to Thymeleaf and are used extensively for data binding, conditional rendering, iteration, and content inclusion in templates.

Conclusion

Using fragments in Thymeleaf is a powerful technique to create modular and reusable components in your web pages. It promotes code reusability, reduces redundancy, and simplifies maintenance. By encapsulating common sections like headers, footers, and navigation bars into fragments, you can create consistent and efficient layouts across your entire application. This approach enhances both development speed and the overall quality of your web project.

Blogs You Might Like to Read!