Skip to main content

UI interfaces

:::info Status Outline — expand with a walkthrough of the generated UI pipeline plus the hand-written Blazor pieces that still surround it. :::

What's generated vs. hand-written

  • Generated: Document and Report Blazor pages (list/create/edit/view, and for reports, the parameterized query UI with grouping/aggregates), driven by Layout/Editors/ Printable attribute families on *Dto classes, emitted through a fluent IUiRenderer/IBlazorUiRenderer abstraction rather than raw RenderTreeBuilder text.
  • Server-driven, not generated or hand-written: the sidebar nav menu — see Navigation (Interfaces) below. Don't reach for a hand-edited .razor file to add a nav entry.
  • Hand-written: login, dashboards, and any bespoke page a generated CRUD/report page doesn't fit.

The sidebar nav menu is server-driven, not a hand-edited .razor file. Your scaffolded repo has one registered Default Interface — a named navigation tree — starting empty (Nodes: []); every configuration needs at least one registered Interface even before it has anything to put in it. Use the add-interface-node skill (in your .claude/skills/) to add an entity/folder/link to the menu, regroup existing entries, gate a node behind a permission, or define a second Interface for a different business role — never hand-edit the nav tree directly.

Page-contract interfaces

INavigationPrefixPage/IWaitingOperationPage/IListPage/IAddPage/IUpdatePage/ IViewPage (plus dictionary/document flavors) give generated and hand-written pages a shared contract. ListForm/HierarchicalListForm collapse to a single page-argument shape.

Custom field types

  • [Dropdown]/[Search] — simple reference selection.
  • [Dialog] — a modal selector, including the composite account+subconto editor for chart-of- accounts fields.
  • [FilePicker] — a Guid? field bound to blob storage (see File storage).
  • Multiselect controls — chip-based flat and hierarchical multi-select, used e.g. in report filters.

Gotchas worth knowing before you start

  • A custom MudBlazor-based input component's resolve-by-id logic must live in OnParametersSetAsync, not OnInitializedAsync, or it won't react to a parameter changing after first render.
  • Naming a parameter Value/ValueChanged while inheriting MudBaseInput<T> throws at runtime even with the new keyword — pick different names.
  • A dialog-select's Clearable doesn't automatically respect ReadOnly when SubscribeToParentForm=false defeats MudBlazor's own default — compute Clearable explicitly from the read-only/disabled state.
  • MudExpansionPanels needs MultiExpansion="true" on the parent, or Expanded="true" on every panel still behaves like an accordion.

See also