Quickstart — Java / Spring Boot
You build the UiPage tree in a controller and return it. The same method
serves two ways, chosen by content negotiation:
Accept: text/html→ no-JS server HTML (SSR, via Handlebars on the JVM)Accept: application/json→ JSON for the SPA client
No template files, no frontend build.
1. Add the dependency
<dependency>
<groupId>ai.mindconnect</groupId>
<artifactId>mc-semantic-ui-core</artifactId>
<version>0.2.2</version>
</dependency>
The core module serves the browser runtime (/sui/renderer.js, /sui/sui.css,
…) from the jar — you ship neither yourself.
Releases are on Maven Central, so the dependency above resolves with no extra
configuration. Snapshots are not published anywhere — to try an unreleased
state, clone this repo and mvn install -DskipTests.
2. Turn SSR on
Server-side rendering is opt-in — the auto-configuration is gated on a flag,
so without it a browser hitting your endpoint gets JSON (or a 406), not HTML:
# application.yml
mindconnect:
sui:
ssr:
enabled: true # registers the UiPage → HTML message converter
Skip this only if you're building a JSON-only backend for the SPA client.
3. Return a UiPage from a controller
@GetMapping(path = "/products", produces = { "text/html", "application/json" })
public UiPage products(@RequestParam(defaultValue = "") String q) {
var table = UiTable.of("products", "Products")
.column(UiColumn.text("sku", "SKU"))
.column(UiColumn.text("name", "Name"))
.rowAction(UiAction.danger("delete", "Delete")
.confirm("Delete this product?")
.dispatch("DELETE", "/products/{id}"));
productService.findAll(q).forEach(p -> table.row(Map.of(
"id", p.getId().toString(), "sku", p.getSku(), "name", p.getName())));
return UiPage.of("/products", table);
}
That's a working, styled, responsive table with a confirmed row action.
"DELETE /products/{id}" above is a string: rename the handler behind it and
nothing tells you. On Spring MVC you can point at the method instead and let
the path and verb be derived from its mapping —
.onClick(trigger(on(ProductController.class).delete(ROW_ID)))
ROW_ID is the sentinel for the {id} each row fills in. See
Naming the handler instead of the URL.
4. Pick a mode
- No-JS / SSR — with the flag from step 2 set, a browser hitting
/productsgets a finished HTML page; the<form>and links work without JavaScript. See Server-side rendering. - Live SPA — add a static
index.htmlshell + a tinyapp.jsthat wires theSuiRendererto theSuiEventBus. The full walkthrough (shell, routing, deep links, auth) is Build an app.
Next
- The building blocks: Node vocabulary, Triggers & actions, Forms & validation.
- A full CRUD example end to end: Shop demo (Postgres) and the File explorer demo.