1. Introduction

In this tutorial, we're going to take a look at variables in Thymeleaf. We'll create a Spring Boot example that will fetch a list of Baeldung articles and display them in a Thymeleaf HTML template.

2. Maven Dependencies

To work with Thymeleaf, we'll need to add the spring-boot-starter-thymeleaf and spring-boot-starter-web dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

3. Web Controller

First, we'll create a web controller with a GET endpoint that returns a page with a list of Baeldung articles.

The method annotated with @GetMapping will take a single parameter – the Model. It holds all the global variables that can be further used inside the Thymeleaf template. In our case, the model will have just one parameter – the list of articles.

The Article class will consist of two String fields, name and url:

public class Article {
    private String name;
    private String url;

    // constructor, getters and setters
}

The return value of our controller's method should be the name of the desired Thymeleaf template. This name should correspond to the HTML file located in the src/resource/template directory. In our case, it'll be src/resource/template/articles-list.html.

Let's take a quick look at our Spring controller:

@Controller
@RequestMapping("/api/articles")
public class ArticlesController {

    @GetMapping
    public String allArticles(Model model) {
        model.addAttribute("articles", fetchArticles());
        return "articles-list";
    }

    private List<Article> fetchArticles() {
        return Arrays.asList(
          new Article(
            "Introduction to Using Thymeleaf in Spring",
            "https://www.baeldung.com/thymeleaf-in-spring-mvc"
          ),
          // a few other articles
        );
    }
}

After running the application, the articles page will be available at http://localhost:8080/articles.

4. Thymeleaf Template

Now, let's move into the Thymeleaf HTML template. It should have the standard HTML document structure with just the additional Thymeleaf namespace definition:

<html xmlns:th="http://www.thymeleaf.org">

We'll use this as a template in further examples, where we'll be replacing just the content of the <main> tag:

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Thymeleaf Variables</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <main>
        ...
    </main>
</body>
</html>

5. Define Variables

There are two ways we can define a variable in a Thymeleaf template. The first option is to take a single element while iterating over an array:

<div th:each="article : ${articles}">
    <a th:text="${article.name}" th:href="${article.url}"></a>
</div>

As a result, we'll get a <div> with several <a> elements corresponding to the number of articles in the articles variable.

Another way is to define a new variable based on another one. For example, we can take the first element of the articles array:

<div th:with="firstArticle=${articles[0]}">
    <a th:text="${firstArticle.name}" th:href="${firstArticle.url}"></a>
</div>

Or we can create a new variable that holds just the article's name:

<div th:each="article : ${articles}", th:with="articleName=${article.name}">
    <a th:text="${articleName}" th:href="${article.url}"></a>
</div>

In the above example, the ${article.name} and ${articleName} fragments are replaceable.

It's also possible to define multiple variables. For example, we can create two separate variables to hold the article name and URL:

<div th:each="article : ${articles}" th:with="articleName=${article.name}, articleUrl=${article.url}">
    <a th:text="${articleName}" th:href="${articleUrl}"></a>
</div>

6. Variables Scope

Variables passed to the Model in a controller have a global scope. This means they can be used in every place of our HTML templates.

On the other hand, variables defined in the HTML template have a local scope. They can be used only within the range of the element that they were defined in.

For example, the below code is correct as the <a> element is within the firstDiv:

<div id="firstDiv" th:with="firstArticle=${articles[0]}">
    <a th:text="${firstArticle.name}" th:href="${firstArticle.url}"></a>
</div>

On the other hand, when we try to use the firstArticle in another div:

<div id="firstDiv" th:with="firstArticle=${articles[0]}">
    <a th:text="${firstArticle.name}" th:href="${firstArticle.url}"></a>
</div>
<div id="secondDiv">
    <h2 th:text="${firstArticle.name}"></h2>
</div>

We'll get an exception during compile-time saying that the firstArticle is null:

org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null

This is because the <h2> element is trying to use a variable defined in the firstDiv, which is out of scope.

If we still need to use the firstArticle variable inside the secondDiv, we would need to define it again in secondDiv or wrap these two div tags in a common element and define the firstArticle in it.

7. Changing a Variable's Value

It's also possible to overwrite a variable's value in a given scope:

<div id="mainDiv" th:with="articles = ${ { articles[0], articles[1] } }">
    <div th:each="article : ${articles}">
        <a th:text="${article.name}" th:href="${article.url}"></a>
    </div>
</div>

In the above example, we redefined the articles variable to have just two first elements.

Note that outside of the mainDiv, the articles variable will still have its original value passed in the controller.

8. Conclusion

In this tutorial, we've learned how to define and use variables in Thymeleaf. As always, all the source code is available over on GitHub.

Generic bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Comments are closed on this article!