Comptus is a Thymeleaf dialect for creating reuseable & encapsulated view components.
Like ViewComponents or Angular components Comptus uses real Java classes to represent a component. Each time a component is used anywhere a new instance of this class ist created and a component template is rendered based upon this instance.
All you have to do is registering Comptus is your Spring Boot Application by doing something like this:
@SpringBootApplication
public class ThymeleafComptusApplication {
@Bean
public ComptusDialect comptusDialect() {
return new ComptusDialect("com.name.of.your.compontents.package");
}
}
A comptus component consists of two parts, a java class which extends
com.innoq.comptus.core.Component
and a HTML template.
E.g. a Button
component would be based upon the following class:
package com.name.of.your.compontents.package;
public class Button extends com.innoq.comptus.core.Component {
public Button(ComponentContext context) {
super(context);
}
}
There also needs to be a Thymeleaf template which is rendered each time the component is used.
The Button's template should be placed under /resources/templates/components/button.html
and could look like this:
<button class="my-button">
<co:slot />
</button>
Now you can use <co:button />
everywhere in your thymeleaf templates like this:
<div>
<co:button>Click me!</co:button>
</div>
This will produce the following HTML:
<div>
<button class="my-button">
Click me!
</button>
</div>
Now let's think about providing data to your component from the outside. Maybe we want to style a button
based upon it's "styling" like <co:button styling="cta">Click me!</co:button>
.
You can access these attributes for your component e.g. inside of your Button's constructor:
private String styling;
public Button(ComponentContext context) {
super(context);
styling = stringAttribute("styling").orElse(null);
}
Now we'll have to use this information to render different HTML in our component template.
This could be done by making the instance variable styling
a public
field.
But this could also be done by providing methods in your component's class:
public String getClassNames() {
return "my-button %s".formatted("cta".equals(styling) ? "primary" : "default");
}
and calling this method from your component template:
<button th:class="${this.classNames}">
<co:slot />
</button>
The th:
attribute based approach doesn't work when you want to pass other objects from your view model to your component. So <co:my-component th:my-data="${mySpecialPOJO}" />
won't work since th:*
would convert everything toString()
at the end and all your component would see is a String.
So Comptus also defines the co:*
attributes on all <co:*>
elements like:
<co:my-component co:my-data="${mySpecialPOJO}" />
Now you can access your object inside your component using:
MySpecialPOJO myData = attribute("my-data", MySpecialPOJO.class).orElse(null);
TBD (see src/test/resources/templates/slots.html)
TBD (see src/test/resources/templates/context.html)
comptus is Open Source software released under the Apache 2.0 license.