Huge shoutout to @wimdeblauwe he helped me to get the library working with java and maven. Go and checkout his book Taming Thymeleaf


Creating a ViewComponent

We just need to add the @ViewComponent annotation to a class and define a render() method that returns a ViewContext. We can pass the properties we want to use in our template.

// HomeViewComponent.java
@ViewComponent
public class HomeViewComponent {
    private final ExampleService exampleService;

    public HomeViewComponent(ExampleService exampleService) {
        this.exampleService = exampleService;
    }

    public ViewContext render() {
        return new ViewContext(
                ViewProperty.of("helloWorld", "Hello World"),
                ViewProperty.of("coffee", exampleService.getCoffee())
        );
    }
}

Next we define the HTML in the HomeViewComponent.html in the same package as our ViewComponent Class.

// HomeViewComponent.html
<html xmlns:th="http://www.thymeleaf.org">
<body>
    <div th:text="${helloWorld}"></div>
    <br>
    <strong th:text="${coffee}"></strong>
</body>
</html>

We can then call the render method in our Controller

// Router.java
@Controller
public class Router {
    private final HomeViewComponent HomeViewComponent;

    public Router(HomeViewComponent HomeViewComponent) {
        this.HomeViewComponent = HomeViewComponent;
    }

    @GetMapping("/")
    ViewContext homeView(){
        return HomeViewComponent.render();
    }
}

If we now access the root url path of our spring application we can see that the component renders properly: thymeleaf-view-component-example

Nesting components:

We can also embed components to our templates with the attribute view:component="componentName".


<div view:component="navigationViewComponent"></div>

When our render method has parameters we can pass them by using the .render(parameter) method.


<div view:component="parameterViewComponent.render('Hello World')"></div>

Parameter components:

We can also create components with parameters. We can either use default values when we pass a null value, get a property from a Service or we can throw a custom error.

@ViewComponent
public class ParameterViewComponent {
    public ViewContext render(String parameter) throws Exception {
        if (parameter == null) {
            throw new Exception("You need to pass in a parameter");
        }
        return new ViewContext(
                ViewProperty.of("office", parameter)
                );
    }
}
// ParameterViewComponent.html
<h2>ParameterComponent:</h2>

<div th:text="${office}"></div>

This enables us to define the properties for our ParameterViewComponent in the HomeViewComponent:

// HomeViewComponent.java
@ViewComponent
public class HomeViewComponent {
    private final ExampleService exampleService;

    public HomeViewComponent(ExampleService exampleService) {
        this.exampleService = exampleService;
    }

    public ViewContext render() {
        return new ViewContext(
                ViewProperty.of("helloWorld", "Hello World"),
                ViewProperty.of("coffee", exampleService.getCoffee()),
                ViewProperty.of("office", exampleService.getOfficeHours())
        );
    }
}
// HomeViewComponent.html
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<body>

<div th:text="${helloWorld}"></div>

<div view:component="parameterViewComponent.render(office,null)"></div>
</body>
</html>

If we now access the root url path of our spring application we can see that the parameter component renders properly:

viewcomponent-parameter

Maven Installation

Add this to your pom.xml:

<project>
    <dependencies>
        <dependency>
            <groupId>de.github.tschuehly</groupId>
            <artifactId>thymeleaf-view-component</artifactId>
            <version>0.3.1</version>
        </dependency>
    </dependencies>
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.html</include>
                </includes>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.3.0</version>
            </plugin>
        </plugins>
    </build>
    <repositories>
        <repository>
            <id>Jitpack</id>
            <url>https://jitpack.io</url>
        </repository>
    </repositories>
</project>