Skip to main content

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

TypePurpose
stackVertical / horizontal layout box
scrollpaneScrolling viewport; optional stick-to-latest live-feed mode
iframeEmbedded browsing context — fold a foreign page into a screen
sectionTabbed or collapsible container
section-entryOne tab + its panel body
pageTop-level envelope; carries toasts and dialogs
headerPage chrome — brand, extras, user widget
app-shellHeader + menu + content, wired and styled

Data display

TypePurpose
tableTabular data — columns, rows, row actions, paging
columnOne table column (label + dataKey + cell template)
rowOne table row (id + data map)
listItem list — icons, descriptions, rich content
detailRead-only key/value view of one record
treeExpand/collapse tree
tree-nodeOne tree entry (label, icon, children, rich content)
textBare text — and the classic patch target

Input

TypePurpose
form<form> with fields, actions and links
fieldOne input — TEXT / SELECT / DATE / BOOLEAN / FILE / …
fieldgroupTitled <fieldset> grouping related fields
uploadDrag-and-drop file drop zone

Actions & navigation

TypePurpose
actionButton, link or icon control with an onClick trigger
linkPlain navigation link
menuNavigation sidebar — expanded, rail, drawer
menu-itemOne menu entry (extends action)
menu-buttonDropdown / context menu

Overlays & feedback

TypePurpose
dialogModal overlay whose body is any node
toastCorner message (not a node — rides on a page or patch)
spinnerBusy indicator
progressProgress bar or ring
iconStandalone 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 typeArtifact
chartmc-semantic-ui-ext-chartabout
diagrammc-semantic-ui-ext-diagramabout
markdownmc-semantic-ui-ext-markdown
json-viewermc-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 widget

UiPage 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.