The node vocabulary
Every screen is built from these 27 node types. A node is a plain object with a
type — which decides how it renders — and an id, which is how you address it
afterwards:
{ "type": "text", "id": "cart-total", "text": "€ 49.00" }
That id flows all the way through: it is the JSON id, the DOM id on the
rendered element, the targetId a patch aims at, the editor's
selection target, and the anchor for form-field names. Give ids you'd be happy to
see in a test.
Every node also carries a display state: omitted means visible,
hidden() takes the node out of layout (display:none) while keeping it in
the DOM — a hidden field's input still rides along in the form submission —
and blank() makes it invisible but preserves its space, so toggling doesn't
shift the layout. Renderers pick this up automatically; a patch that replaces
the node with a visible version brings it back.
Each type exists three times over, kept symmetric: a Java class, a Handlebars template for server-side rendering, and a TypeScript render function for the browser. Adding a type means adding all three — or, in the browser only, one function.
Every type
Each page has the full field reference, a Java and a JSON example, and a live preview you can click.
Layout & structure
| Type | Purpose |
|---|---|
stack | Vertical / horizontal layout box |
scrollpane | Scrolling viewport; optional stick-to-latest live-feed mode |
iframe | Embedded browsing context — fold a foreign page into a screen |
section | Tabbed or collapsible container |
section-entry | One tab + its panel body |
page | Top-level envelope; carries toasts and dialogs |
header | Page chrome — brand, extras, user widget |
app-shell | Header + menu + content, wired and styled |
Data display
| Type | Purpose |
|---|---|
table | Tabular data — columns, rows, row actions, paging |
column | One table column (label + dataKey + cell template) |
row | One table row (id + data map) |
list | Item list — icons, descriptions, rich content |
detail | Read-only key/value view of one record |
tree | Expand/collapse tree |
tree-node | One tree entry (label, icon, children, rich content) |
text | Bare text — and the classic patch target |
Input
| Type | Purpose |
|---|---|
form | <form> with fields, actions and links |
field | One input — TEXT / SELECT / DATE / BOOLEAN / FILE / … |
fieldgroup | Titled <fieldset> grouping related fields |
upload | Drag-and-drop file drop zone |
Actions & navigation
| Type | Purpose |
|---|---|
action | Button, link or icon control with an onClick trigger |
link | Plain navigation link |
menu | Navigation sidebar — expanded, rail, drawer |
menu-item | One menu entry (extends action) |
menu-button | Dropdown / context menu |
Overlays & feedback
| Type | Purpose |
|---|---|
dialog | Modal overlay whose body is any node |
toast | Corner message (not a node — rides on a page or patch) |
spinner | Busy indicator |
progress | Progress bar or ring |
icon | Standalone icon from the swappable icon library |
Beyond the core, four extensions add a node type each. All of them use the same registration mechanism you'd use for your own type — add the artifact and the node appears in the Java model, in Jackson, in the browser renderer and in SSR at once.
| Node type | Artifact | |
|---|---|---|
chart | mc-semantic-ui-ext-chart | about |
diagram | mc-semantic-ui-ext-diagram | about |
markdown | mc-semantic-ui-ext-markdown | |
json-viewer | mc-semantic-ui-ext-json |
Take only the ones you use:
<dependency>
<groupId>ai.mindconnect</groupId>
<artifactId>mc-semantic-ui-ext-markdown</artifactId>
<version>0.2.2</version>
</dependency>
<dependency>
<groupId>ai.mindconnect</groupId>
<artifactId>mc-semantic-ui-ext-json</artifactId>
<version>0.2.2</version>
</dependency>
markdown and json-viewer are also painted on the desktop, each by its own
artifact — see the JavaFX renderer.
A node type and the ability to render it belong together: the core only owns types it can actually draw, which is why charts and diagrams live in modules.
Every type is also rendered live, next to its JSON and Java, in the widget showcase ↗.
page is an envelope, not a widgetUiPage wraps the tree the client navigates to (plus optional toasts, dialogs
and stream state). The browser renderer has no page handler — the event bus
unwraps it and mounts page.node.
So renderer.mount(...) takes a node. Hand it a UiPage and it won't throw:
it renders a <pre> dump of the JSON and logs "no handler for node type".
bus.applyPage(page) is what takes a UiPage; bus.navigate(href) and
bus.start(href) take a URL, fetch the page and apply it.
Extending the vocabulary
The core ships these types; the set is open. A new node is a class, a template and a render function — or, for a browser-only app, just the render function. See step 5 of How it works and the diagram extension, which is this mechanism at full size.