Thymeleaf Layout Dialect: Reusable Page Structures Without Duplicated Markup
Learn how Thymeleaf Layout Dialect lets Spring developers define a base page shell once and inject page-specific content, while keeping HTML prototypes valid and avoiding nested-decoration performance traps.
02 Apr 2026, 19:35 UTC

The Problem: Fifty Copies of the Same Header
If you maintain a Spring MVC application with more than a handful of pages, you already know the pain: every template repeats the same <html>, <head>, navigation bar, and footer. Changing a single nav link means editing dozens of files. Thymeleaf’s standard fragment inclusion helps, but it still leaves you stitching together a page shell on every template. The Layout Dialect takes a different approach: it lets you define the shell once and decorate individual pages into it.
How Decoration Works
The Layout Dialect is an extension to Thymeleaf’s attribute processing. Instead of pulling fragments into a page, you point the page at a base layout using layout:decorate. The base layout contains placeholders defined with layout:fragment, and the content page supplies the matching fragments. Because the dialect operates on standard HTML attributes, your templates remain valid documents that render meaningfully in a browser even before server-side processing.
Three attributes cover most use cases:
layout:decorate— placed on the<html>tag of a content page, it names the base template.layout:fragment— defines a replaceable region in the base layout and the matching content in the page.layout:title-pattern— controls how the page title is assembled from a base pattern and a content-specific variable.
A Worked Example
Add the dialect to a Spring Boot project by including the dependency in your Maven pom.xml. Spring Boot’s auto-configuration detects the JAR and registers the dialect automatically; no XML configuration is required. The example below uses version 2.5.0; verify the latest compatible release for your Thymeleaf version before adding it.
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>2.5.0</version>
</dependency>
Run your standard build command (for example, mvn spring-boot:run) from the project root. You need developer access to modify the build file and restart the application. After startup, confirm the dialect is active by rendering a page that uses layout:decorate; if the attribute is ignored, the raw fragment markup will appear instead of the composed layout.
Next, create a base layout at src/main/resources/templates/layout/base.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">
<title>Site Name</title>
</head>
<body>
<nav>...</nav>
<div layout:fragment="content"></div>
<footer>...</footer>
</body>
</html>
Then a content page at src/main/resources/templates/dashboard.html:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layout/base}">
<head>
<title>Dashboard</title>
</head>
<body>
<div layout:fragment="content">
<h1>Welcome</h1>
</div>
</body>
</html>
When a controller returns the dashboard view name, Thymeleaf processes the decoration at template-rendering time. The final HTML sent to the browser contains the base layout’s <head>, navigation, and footer wrapped around the dashboard content.
Conditional Fragments and the Cost of Nesting
Because fragment resolution happens during template processing, you can conditionally include sections using standard Thymeleaf attributes. For example, a sidebar fragment can check a model attribute:
<aside layout:fragment="sidebar" th:if="${showSidebar}">
...
</aside>
You can also combine this with Spring Security’s Thymeleaf dialect to show or hide regions based on the authenticated user’s roles. The important detail is that the condition is evaluated when the page is rendered, not when the template is parsed, so the decision reflects the current request context.
The main trade-off is performance. Every level of decoration adds processing overhead, and deeply nested layouts on large pages can measurably increase rendering time. The dialect also requires Thymeleaf 3.0 or later; projects still on Thymeleaf 2.x will not recognize the layout: attributes and will need an upgrade before adopting this approach.
What to Check Before You Commit
Start with one layout and two or three content pages. Open the rendered page in a browser and use “View Source” to confirm that the base markup actually wraps the content. Then toggle the model attribute that controls a conditional fragment and verify the section appears or disappears as expected. If you plan to use nested decorations, run a simple rendering benchmark under realistic load before rolling the pattern out broadly. The Layout Dialect removes duplication, but like any template abstraction, it rewards measured use.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.