Kotlin DSL for webforJ
PreviewWrite it in Kotlin. Keep your Java.
The Kotlin DSL builds webforJ UIs with concise, type-safe syntax. Instead of imperative calls, you write declarative code that reads like a description of the screen, and it compiles in the same project as your Java.
The class you know, as a builder
Buttonbecomesbutton()TextFieldbecomestextField()FlexLayoutbecomesflexLayout()Breakbecomes`break`()
Buttons, fields, layouts, dialogs, drawers, lists and HTML elements each have one, named after the class in camelCase.
Same screen, two languages
Read the Java. Then read the Kotlin.
Both sides build the same components with the same webforJ classes. The Kotlin side drops the setters and add() calls: components nest inside each other and configuration happens in blocks.
JavaHelloView.java
@Route("/hello")
public class HelloView extends Composite<FlexLayout> {
private final FlexLayout self = getBoundComponent();
private TextField name = new TextField("What is your name?");
private Button greet = new Button("Say hello");
public HelloView() {
greet.setTheme(ButtonTheme.PRIMARY)
.addClickListener(e ->
Toast.show("Welcome, " + name.getValue() + "!",
Theme.SUCCESS));
self.add(name, greet);
}
}
KotlinHelloView.kt
@Route("hello")
class HelloView : Composite<FlexLayout>() {
private val self = boundComponent
init {
self.apply {
val name = textField("What is your name?")
button("Say hello") {
theme = ButtonTheme.PRIMARY
onClick {
Toast.show("Welcome, ${name.text}!", Theme.SUCCESS)
}
}
}
}
}
What the DSL gives you
Builders, blocks and lambdas
Each builder function creates a component, adds it to its parent container and runs a configuration block. The rest of the DSL follows from that.
Configuration blocks
The block receives the component as this, so you set its properties and call its methods directly.
textField("Email") {
placeholder = "you@example.com" // this.placeholder
required = true // this.required
onModify { validate() } // this.onModify(...)
}
Builders named after components
Each component has a function named after its class in camelCase. Most take the options you set most often, such as a label or a placeholder, before the block.
Nested blocks
Components that hold children accept nested DSL calls inside their block, so the code has the shape of the screen.
Events as lambdas
Listeners use on prefixed methods that take a lambda, such as onClick and onModify.
Scope safety
Children only go into components that support them. Adding to an outer scope by accident does not compile.
Styles and class names
The styles property gives bracket access to CSS properties, the same as setStyle() in Java. Class names are added with +=.
Next to your Java code
Kotlin compiles to JVM bytecode. Use Kotlin composites from Java classes and nest Java components in DSL blocks with add().
Extending the DSL
Your own components, as builders too
Custom components and third-party libraries join the DSL through an extension function on HasComponents. The init helper adds the component to its parent, runs the block and returns it. Composites you build with the DSL get a function the same way.
fun @WebforjDsl HasComponents.starRating(
block: @WebforjDsl StarRating.() -> Unit = {}
): StarRating {
return init(StarRating(), block)
}
How to start
Add Kotlin to a Maven project
The Kotlin DSL is available from webforJ 25.12. A project that already builds with Maven needs a dependency and a plugin.
- 1
Add the dependencies
Add the webforJ Kotlin DSL module and the Kotlin standard library to your pom.xml.
- 2
Add the Kotlin Maven plugin
It compiles your Kotlin and Java sources in one build. No separate Kotlin installation is needed.
- 3
Put Kotlin next to your Java
Kotlin files can go in their own source folder or in the same folder as your Java files.
- 4
Write a view and compile
Write a view with the builders. Maven then compiles your Kotlin alongside your Java.