Reusing Thymeleaf Markup with Fragments: A Practical Guide for Spring Boot MVC
Learn how to reuse Thymeleaf markup with th:fragment and th:replace, including a step‑by‑step example, parameter passing, and trade‑offs for Spring Boot MVC projects.
23 Sept 2026, 06:03 UTC

Why Fragment Reuse Matters
When you build a Spring Boot MVC app, you often end up copying the same header, footer, or navigation markup across dozens of templates. That duplication makes maintenance painful and can introduce subtle bugs when a change is missed in one file. Thymeleaf’s fragment system lets you define a block of HTML once and drop it wherever you need it, keeping your views DRY (Don’t Repeat Yourself) and your changes in one place.
Setting the Stage: th:fragment and Fragment Expressions
A fragment is a named section of a template that you can pull into another template. You declare it with the th:fragment attribute. Inside the fragment you can use th:fragment="name(param1, param2)" to expose parameters that callers can pass. The fragment is referenced in a target template with a fragment expression of the form ~{template :: fragmentName(param1=${value})}.
Key points to remember:
- Fragment names are case‑sensitive.
- Use the tilde (
~{…}) syntax for Thymeleaf 3.x; it resolves the fragment relative to the current template unless you prefix it with a template name. - In Thymeleaf 3,
th:replacereplaces the host element entirely, whileth:insertnests the fragment inside the host element. - Spring Boot auto‑configures Thymeleaf with Spring Expression Language (SpEL), so fragments can access model attributes and beans just like any other template.
Concrete Example: A Reusable Footer with Dynamic Text
Let’s walk through a minimal Spring Boot project that demonstrates fragment reuse. The project uses Spring Boot 3.x and Thymeleaf 3.x.
1. Create the Layout Fragment
Place the following in src/main/resources/templates/layout.html:
Default Title
Site Header
© 2026 My Company
Notice how the header and footer fragments accept parameters. The main section uses th:insert to embed a content fragment that will be supplied by the page template.
2. Build a Page Template that Uses the Fragments
In src/main/resources/templates/home.html write:
Home
Welcome to the home page! Today is date.
Explanation of the key lines:
th:replace="layout :: header('Home Page')"tells Thymeleaf to replace the<html>element with theheaderfragment fromlayout.html, passing the stringHome Pageas thetitleparameter.- The
contentfragment defines the body of the page. It will be inserted into themainsection oflayout.htmlby theth:insertcall inside the layout. - The
footerfragment is inserted withth:replace, which replaces the<div>that contains it. The year is computed using Thymeleaf’s date utility object.
3. Add a Simple Controller
In src/main/java/com/example/demo/HomeController.java:
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("pageTitle", "Welcome to My Site");
return "home";
}
}
When you run the application and navigate to /, Thymeleaf will:
- Render
layout.htmlfirst, pulling in theheaderandfooterfragments. - Insert the
contentfragment fromhome.htmlinto themainsection. - Replace the host element for
th:replacecalls, ensuring the final HTML only contains the desired markup.
Trade‑offs and Limitations
- Relative vs Absolute Paths: If you reference a fragment without a template prefix (e.g.,
~{footer :: main}), Thymeleaf resolves it relative to the current template. This works well when the fragment lives in the same file, but for shared fragments across modules you should use an explicit template name (e.g.,~{layout :: footer}). Forgetting the prefix can lead to runtime errors that are hard to trace. - Fragment Name Sensitivity: A typo in the fragment name or parameter list will not be caught at compile time; you’ll see a blank page or a Thymeleaf error at render time. Use IDE support or unit tests to catch these quickly.
- Insert vs Replace Semantics: In Thymeleaf 3,
th:insertkeeps the host element, whileth:replaceremoves it. Mixing these in older projects that migrated from 2.x can produce confusing layouts. Always verify the intended behavior by inspecting the rendered HTML. - Performance Overhead: Each fragment call causes an additional template parse. For very large sites with many fragments, consider caching the fragment output or using layout dialects that optimize this process.
Actionable Checklist for Your Next Project
- Define reusable blocks in a dedicated
layout.htmlusingth:fragment. - Expose parameters that vary per page (e.g., titles, user names).
- Reference fragments in page templates with
th:replaceorth:insert, using absolute template names for cross‑module reuse. - Pass dynamic values from the controller into the model and reference them inside fragments.
- Run the application and inspect the final HTML to confirm that host elements are replaced or preserved as expected.
- Add unit tests that render a fragment standalone to catch name and parameter mismatches early.
By following these steps, you’ll keep your view layer clean, maintainable, and easily extensible as your application grows.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.