Skip to main content

Semantic UI

Stop wasting your time with complicated frontend frameworks.

Why did UI frameworks get this complicated? All you wanted was an input screen and a table. Instead you're picking a bundler, learning a reactivity model, reasoning about signals and effects, wiring a router, mirroring your validation rules in a second language — before a single field shows up on screen.

semantic-ui throws that out. You describe the screen as a small, typed tree — UiTable, UiForm, UiField, … — and a ready-made renderer draws it. Data-driven, with a clean split between logic (yours, where your data already is) and design (one CSS system, shared by every screen). No components. No state. No build step.

semantic-ui flips the relationship:

React / Angularsemantic-ui
You writecomponents (JSX / templates)data — a typed UiNode tree
Markup + logicmixed inside componentssplit: model = structure, CSS = look
Statehooks / signals / Reduxnone — UI = render(your data)
Stylingper component, drifts over timeone shared CSS design system
Runtime / builda framework + toolchain to learna <script>, or plain JSON
Interactivitywire up handlers + state yourselfdeclarative triggers (fetch / patch / navigate)

The model is plain typed JSON. A small TypeScript renderer turns the tree into a live, interactive UI in the browser; on the JVM a matching Handlebars renderer produces the same markup as no-JS server HTML, and a JavaFX renderer draws the very same tree as a native desktop client. One model, many renderers: a live app, no-JS HTML, a desktop client, and a built-in visual editor. Where the data comes from is up to you — a JavaScript object in the page, or any backend that emits the JSON.

Semantic UI — how it works

The rightmost box is not hypothetical. Below is one UiNode tree, drawn twice: on the left by the JavaFX renderer as a native desktop window, on the right by the browser renderer — live, right here on this page. The tree on the right was serialised straight out of the running Java demo, so it really is the same model and not a lookalike.

The tree as a native JavaFX desktop window

JavaFX — a real TableView, Button, ProgressBar.

Browser — real DOM, and interactive: add or delete orders and the fulfilment bar moves with them.

The two shapes you'll write​

Everything is one of two payloads. Build them with the Java API, or emit the same JSON from anything — they are the identical wire format.

UiPage — a whole screen. What you return when the user navigates:

// The table in both screenshots above — this is the whole source.
UiPage.of("/orders",
UiTable.of("orders-table", "Orders")
.column(UiColumn.text("id", "Order").asSortable())
.column(UiColumn.text("product", "Product"))
.column(UiColumn.number("amount", "Amount"))
.column(UiColumn.text("status", "Status"))
.action(UiAction.primary("add-order", "Add order")
.onClick(UiTrigger.invoke("addOrder")))
.rowAction(UiAction.danger("delete-order", "Delete")
.onClick(UiTrigger.invoke("deleteOrder")))
.row(Map.of("id", "1001", "product", "Keyboard",
"amount", "89.00", "status", "shipped")));

That is the entire source of the table you saw twice at the top of this page — once as a JavaFX window, once live in the browser. No build step, no components, nothing else on the page.

UiPatch — a surgical update. What you return to change part of the screen without resending it. Each operation targets a node by id (REPLACE, APPEND, CLEAR, REMOVE), and it can carry a toast:

UiPatch.of()
.patch(UiPatch.Operation.replace("cart-total",
UiText.of("cart-total", "€ 49.00")))
.toast(UiToast.success("Added to cart"));

That's the whole interaction model: a node carries a trigger, the trigger calls you, you answer with a UiPage or a UiPatch. Nothing else to learn.

Draw it instead — and download the running app​

You don't have to write that JSON by hand. The visual editor runs entirely in your browser — no install, no account, no backend — and it edits the same tree this page has been describing: drag nodes, set properties, watch the live preview.

Then export it as a runnable application. Pick your target and download a zip:

ExportWhat you get
Static HTMLAn index.html plus the runtime. Open it, or drop it on any static host.
Spring BootA Maven project with a controller per page. mvn spring-boot:run.
Node.jsAn Express app with a route per page. npm install && npm start.

The export is a plain, hand-written semantic-ui app — not a copy of the editor and not a runtime that interprets a saved file. It is the starting point you would otherwise have typed yourself, which also makes the editor a reasonable way to learn the model: build a screen, export it, read the code.

Choose your path​

semantic-ui fits four setups. Pick the one that matches your stack and start there — all four share the same core concepts.

  • Java / Spring Boot — a controller returns a UiPage; get no-JS server HTML (SSR) and/or a live SPA client from the same code.
  • JavaScript client only — no backend at all: load the runtime from a <script> and render UiNode literals in the browser.
  • Node.js backend — an Express (or any) server emits the UiPage JSON; the browser renderer paints it.
  • JavaFX desktop client — no browser at all: the same tree painted as a native desktop window, with local Java handlers.
Try it live

Open the interactive widget showcase ↗ — a fully static page (no backend) that renders every UiNode, each shown next to the JSON the renderer consumes and the equivalent Java builder.

Why it feels different​

Frontend development has piled up a mental load that's wildly out of proportion for most CRUD-shaped business apps: build toolchain, reactivity model, state management, routing, form-state, server-state cache, a component library, validation — much of it duplicated on both sides of the wire.

semantic-ui takes a different stance:

  • You write data, not components — no JSX, no lifecycle, no re-render model. A UiTable literal is the table.
  • No state management — the UI is a pure function of your data.
  • Structure is data, design is CSS — they can't tangle; you get a consistent design system by default. Business logic stays where your data is.

What you can build with it​

Most application UIs are structured screens — and structured screens are exactly what a typed tree describes well:

  • Admin / backoffice, ERP / CRM, accounting, HR, order entry
  • Workflow, wizard and case-management UIs
  • B2B SaaS dashboards, tables, reporting surfaces
  • Customer-facing CRUD and shop frontends — the design system is yours to restyle; see the shop demo
  • Editors and canvases — the visual editor and the diagram extension are themselves built this way
  • Streaming / chat surfaces, via UiPatch over SSE
  • LLM-agent-operable UIs — a finite vocabulary is far easier for an agent to drive than free-form HTML

The kanban extension (a board whose cards are dragged between lanes) and the calendar extension (month, week and day views of events) follow the same shape: node types and both painters in one module, rendered server-side as well, with the browser bundle adding what a page cannot do without JavaScript — the dragging, the picking.

If a screen can be described as "these fields, this table, these actions", it fits. And when one corner of a page needs something bespoke, you don't leave the framework: add a node type (or drop in a UI island) and keep the rest.

Core concepts (shared by all three paths)​

Setup lives in the quickstart for your stack — pick one under Choose your path above.