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

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.