🚀 DataStar version: 1.0.4
This project includes a demo web application featuring examples from Data-Star, running on Ktor and http4k and using the Type-Safe Hypermedia-First DSL for Reactive Backend-Driven Web Applications to generate HTML.
HtmlFlow DSL provides type-safe backend handlers for DataStar actions.
In the following samples, note how the action get is attached to a handler given by a function reference, this function being annotated
with Path, from Jakarta, where the resource location for the
request is specified.
HtmlFlow DSL also provides a type-safe way to define Datastar attributes in Kotlin. Next is a sample of the Counter example with a strongly typed signal and another one from Active Search using events and modifiers:
|
|
Note that the count variable is of type Signal
and simply binds to the data-text in a type-safe way,
regardless of the name passed to the Signal constructor.
|
Modifiers such as debounce are added inside a lambda using
builders, following an idiomatic Kotlin style.
|
Also, HtmlFlow DSL supports strongly typed DataStar expressions,
allowing their composition with the infix operator and,
such as in the expression !fetching and get(::clickToLoadMore).
Note how the JavaScript expression for the onclick event handler (right side)
is expressed in Kotlin through HtmlFlow in a type-safe way:
|
|
Change to the datastar-examples directory and run the application with Gradle. The application will start two servers, one for Ktor and another for http4k, each running the same examples.
cd ./datastar-examples
Run with:
./gradlew run
Then open http://localhost:8080 for the ktor server and http://localhost:8070 for http4k in your browser.
Check all examples from the index page and corresponding HtmlFlow view definitions:
- Active Search - ActiveSearch.kt
- Bulk Update - BulkUpdate.kt
- Click To Edit - ClickToEdit.kt
- Click To Load - BulkUpdate.kt
- Counter Via Signals - CounterViaSignals.kt
- Delete Row - DeleteRow.kt
- File Upload - FileUpload.kt
- Infinite Scroll - InfiniteScroll.kt
- Inline Validation - InlineValidation.kt
The petclinic-htmlflow module contains an implementation of the Spring Petclinic application using HtmlFlow Kotlin views and DataStar hypermedia controls; it replaces the previous Thymeleaf templates. The goal is to preserve the original Petclinic domain and features while exploring a backend-driven, hypermedia-first UI model that is:
- Type-safe: views are expressed in Kotlin using the HtmlFlow DSL.
- Server-driven: DataStar actions and signals enable server-initiated UI updates.
- Incremental and efficient: updates can patch page fragments (for example table rows) instead of reloading whole pages.
Run the Petclinic application with Gradle:
cd ./petclinic-htmlflow
./gradlew bootRun
Open http://localhost:8080 in your browser. The application supports the usual Petclinic features (owners, pets, visits) implemented with HtmlFlow/DataStar rather than Thymeleaf.
Below is a simplified comparison showing the traditional Thymeleaf findOwners form and an equivalent HtmlFlow view that uses data binding and a Debounce modifier to drive the search results from the server.
Thymeleaf (classic form)
<h2>Find Owners</h2>
<form th:object="${owner}" th:action="@{/owners}" method="get">
<div id="lastNameGroup">
<label>Last name</label>
<div>
<input th:field="*{lastName}" size="30" maxlength="80"/>
<span class="help-inline">
<div th:if="${#fields.hasAnyErrors()}">
<p th:each="err : ${#fields.allErrors()}" th:text="${err}">Error</p>
</div>
</span>
</div>
</div>
<button type="submit">Find Owner</button>
<a th:href="@{/owners/new}">Add Owner</a>
</form>
HtmlFlow + DataStar (server-driven)
h2 { text("Find Owners") }
val lastName = dataSignal("lastName")
dataText { +" Searching for users with last name $lastName " }
input {
dataBind(lastName)
dataOn(Input) {
get(::searchhOwners)
modifiers { debounce(200.milliseconds) }
}
}
table {
tableHead()
tbody { tableBody() }
}
a { attrHref("/owners/new"); text("Add Owner") }
- Server-driven UIs keep view code on the backend, reducing the need for a separate frontend codebase while still delivering interactive behavior.
- Fine-grained patches (signals/events) reduce network traffic compared with full page reloads.
- Kotlin + HtmlFlow provide compile-time guarantees for view changes and make refactors safer.