Graphical User Interface
Build reactive user interfaces entirely in C#. Controls are immutable records, rendered server-side and streamed to the browser — no JavaScript framework, no manual DOM updates.

How it works

MeshWeaver's UI model has three interlocking ideas. Once they click, building rich interfaces is surprisingly straightforward.

1. Controls are immutable records

Every control is a plain C# record. With* methods return new instances — the original is never mutated:

var button1 = Controls.Button("Click me");
var button2 = button1.WithId("myButton");  // button1 is unchanged
button2

This means control definitions are pure data. You can safely share, copy, and compose them without worrying about side effects. A control doesn't render anything until it's placed in a layout area.

2. Rendering is declarative and area-based

Instead of describing how to update the DOM, you describe what each named area should show. Only the affected area re-renders when its data changes — sibling areas are never disturbed:

Controls.Stack
    .WithView(Controls.Html("<h1>Dashboard</h1>"))      // Static — rendered once
    .WithView(liveDataStream.Select(d => ShowData(d)))  // Dynamic — updates on each emission
    .WithView(Controls.Button("Refresh"))               // Static — rendered once

Container structure is fixed; only observable-backed slots re-render.

3. Reactivity comes from IObservable<T>

Pass any IObservable<T> as a view and the content updates automatically. Subscriptions are created and disposed for you as areas mount and unmount:

var counter = Observable.Interval(TimeSpan.FromSeconds(1));

Controls.Stack
    .WithView(counter.Select(n => Controls.Label($"Count: {n}")))

No callbacks to wire up. No teardown code to write — the counter below is ticking live.


Live example

Controls.Stack
    .WithView(Controls.Html("<b>MeshWeaver UI — live from the kernel</b>"))
    .WithView(Controls.Markdown($"Rendered at **{DateTime.Now:HH:mm:ss}** — controls are plain C# records."))
    .WithView(Controls.Button("A static button (no action wired here)"))

Where to go next

Browse the full set of controls, layout primitives, and data-binding guides:

Topic Description
Layout Areas Named rendering slots — how the hub decides what to show and where
Container Controls Stack, Tabs, Toolbar, Splitter, Layout — composing areas together
Layout Grid CSS-grid-based two-dimensional layouts
Data Binding Two-way reactive binding via JSON Pointers — the contract every backend area must follow
Static vs. Dynamic Views When areas re-render and how to control update frequency
Displaying Times Stored instants are UTC — render them in the viewer's own zone, and which values must NOT be converted
DataGrid Tabular data with sorting, filtering, and row actions
Form Input Controls Checkboxes, switches, date pickers, list selectors, radio groups, node picker — each rendered live
Badges, Icons & Status Badges, icons, progress bars, spacers, menu items, and card skins
Navigation Menus NavMenu, NavGroup, NavLink — collapsible side navigation
Code, Diff & Markdown Editors Monaco-backed source editing, diffs, and markdown authoring
Node Cards & Catalogs Cards, thumbnails, live node collections, and grouped catalogs
Mesh Search & Catalogs One URL-driven Search area per node — group by namespace/type/category, drill down, embed with @@
Configurable Home & Space Pages Your home / Space Overview is one editable markdown page that embeds regions with @@
Editor Auto-generated editable forms from C# records
Attributes Declarative style, visibility, and validation annotations
Side Panel Slide-in panels for detail views and settings
Reactive Dialogs Modal dialogs backed by observable state
Node Menu Context menus on mesh nodes
React Frontend The client-side React frontend — same UiControl contract, rendered in the browser over gRPC-web: running it, rendering, theming, chat, testing
Custom Blazor Controls Extend the Blazor portal with your own control — a UiControl subclass + a BlazorView, registered with WithView; ships from core, a pack, or a plugin at runtime
Custom React Controls Extend the React renderer with your own control — server-side $type + a React registry entry
Reconnecting…
The server was updated. Reloading the page to pick up the latest version.