Reusing markup with Thymeleaf fragments: definition, inclusion, and parameters
Learn how to define Thymeleaf fragments with th:fragment, reuse them via th:insert/th:replace, pass parameters, and avoid common pitfalls like deprecated th:include and parameter shadowing.
16 Jan 2026, 19:52 UTC

Useful answer
To avoid repeating header, footer, sidebar, or any other markup across multiple pages, define a reusable piece of HTML as a Thymeleaf fragment with th:fragment and insert it where needed using th:insert or th:replace. Fragments can also accept parameters, letting you treat them like small server‑side components.
How fragments work – a worked example
First create a fragment file, e.g. src/main/resources/templates/fragments/common.html:
<!-- fragments/common.html -->
<div th:fragment="greet(name)">
Hello [[${name}]]!
</div>
The th:fragment attribute names the reusable block and declares a parameter name. Inside the fragment you can reference that parameter with standard Thymeleaf expression syntax (${name}).
Now use the fragment from any other template. For a full‑replace (the host tag is removed and the fragment takes its place) use th:replace:
<!-- src/main/resources/templates/pages/welcome.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
Welcome
</head>
<body>
</body>
</html>
The expression ~{fragments/common :: greet('Visitor')} resolves to the fragment named greet in fragments/common.html and passes the string literal 'Visitor' as the name parameter. At render time Thymeleaf evaluates the fragment with the supplied argument and produces:
<div>Hello Visitor!</div>
If you want to keep the host tag and merely insert the fragment’s markup inside it, use th:insert instead:
<section th:insert="~{fragments/common :: greet('Visitor')}"></section>
Result:
<section>
<div>Hello Visitor!</div>
</section>
Limits and common mistakes
- Deprecated
th:include: In Thymeleaf 3 the attributeth:includewas removed (it only inserted the fragment’s children). Using it in a Thymeleaf 3 project will cause a template‑parsing error. Replace it withth:insertif you need the children only, orth:replacefor full replacement. - Parameter shadowing: When you declare a fragment parameter (e.g.,
th:fragment="row(product)"), any variable with the same name that exists in the calling template’s context is hidden inside the fragment. If you rely on the outerproductvariable, rename either the parameter or the outer variable to avoid confusion. - Deep nesting hurts readability: Chaining many parameterized fragments can make it difficult to trace which variables are supplied where. Keep fragment signatures short (one or two parameters) and document the expected variables in a comment near the fragment definition.
- Template caching in development: Spring Boot enables Thymeleaf template caching in production. While caching improves performance, it means that changes to a fragment file are not visible until the application restarts or the cache is cleared. During development set
spring.thymeleaf.cache=falseinapplication.propertiesto see edits immediately.
Verification steps
- Add the fragment file
fragments/common.htmlwith thegreet(name)fragment as shown above. - Create a test page that uses both
th:replaceandth:insertto call the fragment with different arguments. - Start the application (or use
spring.thymeleaf.cache=false) and request the test page. - View the rendered HTML source and confirm:
- The
th:replacecall produces only the fragment’s markup (no host tag). - The
th:insertcall wraps the fragment inside the host tag. - Passed parameters appear correctly in the output.
- The
- To verify caching behavior, edit the fragment text, reload the page, and observe whether the change appears immediately (with caching disabled) or only after a restart (with caching enabled).
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.