NE.Standard

Views

A view is a UIViewBase subclass that builds a component tree — the framework compiles it once and renders it to the platform. Every view also implements IUIViewDefinition, whose static ViewKey is the stable name route registration and view lookup use.

internal sealed class CounterView : UIViewBase, IUIViewDefinition
{
    public static string ViewKey => "counter";

    protected override IVisualComponent CreateContent()
        => new ContainerComponent()
            .AddChild(new TextComponent().BindTitle(nameof(CounterController.Count)));
}

Regions

A view builds up to five regions by overriding the corresponding Create* method — all protected virtual except CreateContent, which is abstract and required:

  • CreateHeader()
  • CreateFooter()
  • CreateLeftSide()
  • CreateRightSide()
  • CreateContent() — the only region every view must supply.

Each returns an IVisualComponent? (null for a region the view does not use) except CreateContent, which returns one. Regions are built lazily, once, and cached.

Title and options

Title (defaults to the type name) and Options (UIViewOptions.Default unless overridden) are virtual properties a view overrides directly:

public override string Title => "Dashboard";

public override UIViewOptions Options => new()
{
    StickyHeader = true,
    ScrollContentOnly = true,
    NotificationPlacement = UINotificationPlacement.Top
};

UIViewOptions says what the view wants from its own shell, not from any component in it:

Property Effect
StickyHeader The header region stays at the top of the viewport while the content scrolls under it.
ScrollContentOnly The page keeps the viewport's height; header and sides stand still and only the content region scrolls.
NotificationPlacement Which corner this view's toasts stack in — Bottom (default) or Top.

Dialogs

CreateDialogs() declares the view's dialogs, rendered closed by the shell and opened by key from a command (see interactions and effects for the effect that opens one). Each UIDialog names a key, its content, and how it presents:

protected override IReadOnlyList<UIDialog> CreateDialogs()
    => [
        new UIDialog
        {
            Key = "confirm-delete",
            CloseOnBackdrop = false,
            CloseOnEscape = false,
            Content = new ContainerComponent()
                .AddChild(new TextComponent().SetTitle("Delete this build?"))
        }
    ];

UIDialog properties: Key and Content are required; Surface (UISurfaceStyle, default Raised) is what the panel is made of; Placement (UIDialogPlacement: Center, Left, Right, Top, Bottom, default Center) is where it stands — centred or as a sheet against one edge; Modal (default true) blocks interaction with the view underneath; CloseOnBackdrop and CloseOnEscape (both default true) are the two dismissals a destructive confirmation usually turns off.

The placement grid

Every visual component has a Placement — its cell(s) in a 24-column grid (UIGridPlacement.GridColumns). SetPlacement is the fluent entry point:

new TextComponent()
    .SetPlacement(1, 1, 24, 1)
public TComponent SetPlacement(int column, int row, int columnSpan = 1, int rowSpan = 1,
    UIGridPlacement? sm = null, UIGridPlacement? md = null, UIGridPlacement? xl = null, UIGridPlacement? xxl = null)

column/row are the starting cell, columnSpan/rowSpan how many cells the component occupies. The four optional arguments after them override the placement per breakpoint — sm, md, xl, xxl, built with UIGridPlacement.At(column, row, columnSpan, rowSpan).

A child of a container with no placement of its own spans all twenty-four columns — one to a row. The two wrapping layouts read the span differently: in a WrapPanel, and in an ItemsView whose layout is Wrap, a child with no placement takes its content's width and the line wraps where the room ends, and a placement makes it that share of the width instead — a template root with .SetPlacement(1, 1, 6, 1) is four items to a line.

This is Placement's own type, UIResponsive<UIGridPlacement>, and the same shape backs every responsive property on a component (Width, Margin, and so on): a required Base value plus optional per-breakpoint overrides (Sm, Md, Xl, Xxl). An unset breakpoint falls back to the next narrower one that is set, down to Base — mobile-first. UIResponsive<T>.Create(value, sm, md, xl, xxl) builds one explicitly, and a bare T converts to it implicitly (FromValue).

Component ids

A component's Id is either the string passed to its constructor or a generated u<N> from a process-wide counter. HasAuthoredId says which:

new StackPanelComponent("sidebar")

An authored id is what the client's small per-viewer preferences (a collapsed menu, a split panel's tracks) key off in localStorage; a generated id means nothing between two runs, so a component with no authored id stores nothing. Give one to anything the reader would expect to remember its own state across a reload.

The fluent style

Every component method returns the component itself (TComponent, the generic self-type), so calls chain:

new ContainerComponent()
    .SetPadding(new UIThickness(8))
    .AddChild(new TextComponent()
        .SetTitle("Hi")
        .SetPlacement(1, 1, 24, 1)
    )
    .SetPlacement(1, 2, 24, 1)

The naming is consistent across every component:

  • Set* assigns an authored value — a plain CLR value the view controls once, at compile time.
  • Bind* (generated per bindable property) or the raw Bind(property, path, scope, mode) ties a property to a controller path instead — see binding.
  • Configure(Action<TComponent>) runs arbitrary code against the component inline, for the rare case a fluent method does not cover.
  • AddChild(IVisualComponent) / AddChildren(...) append children to a container component (ContainerComponentBase<T> and its descendants).

Context menu

SetContextMenu(IVisualComponent contextMenu) sets what opens on a right-click, normally a MenuComponent; ShowContextMenu (bindable, default true) switches the mechanic off without removing the authored menu.

Visibility

Visibility is UIResponsive<UIVisibility>?, and UIVisibility has three values:

Value Effect
Visible Drawn, and taking part in layout, hit-testing, focus and assistive technology.
Hidden Not drawn, but still holding its place — the layout around it does not move.
Collapsed Gone from the layout as well: everything after it closes the gap.

Theme

Theme (UIThemeMode?) forces a component's subtree into Light or Dark regardless of the session's own theme; null (the default) inherits. This is a per-component override — the session-wide setting is a separate mechanic (SetThemeEffect, see interactions and effects).

Inline text markup

A description or a tooltip may carry a small inline markup, parsed by UIInlineMarkup (parity-tested against the client's own parser):

Syntax Produces
**bold** Bold
*italic* Italic
__underline__ Underline
~~strikethrough~~ Strikethrough
`code` Inline code
[label](url) A link — url must pass UIInlineMarkup.IsSafeUrl (relative, #, ?, ., or http/https/mailto/tel)
![glyph] An icon, named by glyph name only — never a URL
[caption]{text} A fold: a caption with collapsible text, which may itself contain markup

A marker is escaped with a backslash (\*) to appear literally; UIInlineMarkup.Escape(text) escapes every marker in a value before it is substituted into a localized string. UIInlineMarkup.ToPlainText(text) strips the markup for a place that takes plain text only, such as an aria-label.

Where to go next