You can run a MDriven Turnkey application with the Blazor UI engine, test a ViewModel through its Blazor route, and configure that engine as the application default.
Blazor in MDriven Turnkey
Blazor is a web UI framework used by Turnkey to render your ViewModels in the browser. Turnkey provides two Blazor routes:
| UI engine | Route pattern | Use |
|---|---|---|
| Client-side Blazor | /Appl/ViewModelName/RootIdentifier
|
Use the appl controller to render a ViewModel with the client-side Blazor implementation.
|
| Server-side Blazor | /Appli/ViewModelName/RootIdentifier
|
Use the appli controller to render a ViewModel with the server-side Blazor implementation.
|
For example, to open the SeekerThings ViewModel without a root object, use:
http://localhost:5020/Appl/SeekerThings/$null$
For the server-side implementation, use:
http://localhost:5020/Appli/SeekerThings/$null$
Test client-side Blazor
If you already have an AngularJS Turnkey URL, replace the AngularJS controller and hash route with the client-side Blazor route.
- Start with an AngularJS URL such as
http://localhost:5020/App#/SeekerThings/$null$. - Replace
App#withAppl. - Open
http://localhost:5020/Appl/SeekerThings/$null$.
The Blazor route does not use the AngularJS # route marker. This makes it possible to test the same ViewModel in Blazor while keeping the AngularJS UI available.
Make Blazor the default UI engine
Configure the application-wide UI engine through GlobalMainUIEngine:
| Goal | Setting value |
|---|---|
| Make client-side Blazor the default | appl
|
| Make server-side Blazor the default | appli
|
Restart the application after changing the setting. The UI-engine selection is read at application startup.
The GlobalBlazorClient setting can also control whether the Blazor client is preferred as the default. Use the application UI-engine configuration to make the intended default explicit.
Choose the appropriate route
Use Appl when you want the client-side Blazor implementation. Use Appli when you need the server-side Blazor implementation.
Keep this choice at the application level. A ViewModel-level switch between AngularJS and Blazor is not available. If your solution contains framework-specific custom components, test each affected ViewModel in the selected UI engine before making Blazor the default.
DataGrid row virtualization
The Blazor DataGrid is based on QuickGrid and adds filtering. QuickGrid row virtualization is enabled.
Virtualization requires the grid's configured row height to match the height that your CSS actually renders. Set the CSS custom property --quickgrid-row-height to the intended row height, and make the row styling use that same height.
For example, if your grid rows are 30 pixels high:
:root {
--quickgrid-row-height: 30px;
}
A mismatch can cause the grid to flicker while scrolling. The default row height is 28 pixels, so retain that value unless your CSS changes the rendered row height.
Extend a Blazor UI
You can add a custom Blazor component to a specific tagged ViewModel column. Build the component as a Blazor WebAssembly component, make its output available to the Turnkey application, and assign the Blazor_Ext_Component tagged value to the column where the component should render. For the required component parameters, deployment files, tagged-value format, and development-path options, see Documentation:EXT ComponentsBlazor.
For example, use a column-specific component when one ViewModel field needs a specialized editor or visualization while the remaining fields use the standard Blazor controls.
If you need to replace standard Blazor components broadly, or select replacements through your own switch logic, implement the broker described in Documentation:Blazor IComponentTypeSwitchBroker. This is different from assigning one custom component to one tagged column.
View metadata for Blazor
Blazor needs ViewModel metadata in the browser so that it can build the UI. Turnkey exposes per-view metadata through:
http://<YourSite>/Turnkey/ViewMetaBlazorClient?view=NameOfViewModel
The response is XML and describes UI-facing information such as names, suggested placement, suggested control type, and labels. It does not expose sensitive implementation information. See Documentation:ViewMeta for the metadata endpoint and its purpose.
Related UI behavior
Blazor renders the ViewModel UI, while account operations such as registration and login remain handled by the server-side account controller. Do not treat these operations as client-side ViewModel actions.
Use the standard Turnkey documentation for shared UI behavior such as text formatting, Instant Page Loader, and standard shortcut keys.
See also
- Documentation:EXT ComponentsBlazor
- Documentation:Blazor IComponentTypeSwitchBroker
- Documentation:ViewMeta
- Documentation:Text formatting
- Documentation:InstantPageLoader
- Documentation:TurnkeyAppStandardShortcutKeys
Custom Blazor components
Custom Blazor components
MDriven documents an extension mechanism for injecting custom components on specific tagged ViewModelColumns. Components for this mechanism must be built as Blazor WebAssembly components.
A custom component can be created in a Razor component library and included in the Blazor application. The component project can use MDriven.SharedInterfaces.WebAssembly. Alternatively, it can reference MDriven.Components.WebAssembly and inherit from MDCompBase.
To participate as an MDriven Turnkey component, the component needs the documented parameter contract, or it can inherit from MDCompBase. Documented parameters include CompType, XElement, BindInfoColumn, BindInfoNesting, ContextIVMClassObject, RendersAction, RendersActionThatUseAbstractAction, IsGridCell, IsGridEditable, ViewClient, and FlexStyling.
After building, include the component assembly and the browser-side files generated by the Blazor application build. The documentation notes that the generated files can be found under the application's wwwroot/_framework output, and that publishing may be required to create all needed files. Copy the required files to EXT_ComponentsRazor in the Turnkey application.
For a component rendered in a grid cell, IsGridCell can be used to avoid rendering standalone content such as a label.
Other front-end frameworks
The supplied documentation describes a Blazor WebAssembly component extension path. It does not document a React component format, a React wrapper, or a procedure for rendering React components in a tagged ViewModelColumn. Do not assume that a React component can use the documented Blazor component mechanism without a separately supported integration approach.
Standard-component replacement
The documentation distinguishes targeted injection on tagged ViewModelColumns from replacing standard components more broadly. It refers readers who want to replace standard components to the Blazor IComponentTypeSwitchBroker documentation.
Customize Blazor components and manage component context
Customize Blazor components and manage component context
You can replace the rendering of a tagged ViewModel column with your own Blazor WebAssembly component when you need custom markup, styling, or behavior in an MDriven Turnkey Blazor client.
Choose the replacement scope
Use a targeted component when one ViewModel column needs a different renderer. For example, use a targeted component for one column that needs a specialized presentation while other columns continue to use the standard component.
Use IComponentTypeSwitchBroker when you need to replace all, or a selected set, of standard components according to switch logic that you define.
| Need | Customization method |
|---|---|
| Replace the component rooted at one column | Set the Blazor_Ext_Component tagged value on that column. See Blazor external components.
|
| Replace standard components across the client according to your own logic | Implement IComponentTypeSwitchBroker and configure GlobalBlazorClientComponentOverride. See IComponentTypeSwitchBroker.
|
Build a component that receives MDriven context
Build the component as a Blazor WebAssembly component. A component can inherit MDCompBase from MDriven.Components.WebAssembly so that it receives the MDriven Turnkey component support.
If you do not inherit MDCompBase, declare the parameters that MDriven uses to provide component context. The following example renders differently when MDriven places the component in a grid cell:
@using System.Xml.Linq
@using MDriven.SharedInterfaces.WebAssembly
<div class="my-component">
@if (!IsGridCell)
{
<strong>Standalone component</strong>
}
else
{
<span>Grid-cell component</span>
}
</div>
@code {
[Parameter] public string CompType { get; set; }
[Parameter] public XElement XElement { get; set; }
[Parameter] public string BindInfoColumn { get; set; }
[Parameter] public string BindInfoNesting { get; set; }
[Parameter] public IVMClassObject ContextIVMClassObject { get; set; }
[Parameter] public string RendersAction { get; set; }
[Parameter] public string RendersActionThatUseAbstractAction { get; set; }
[Parameter] public bool IsGridCell { get; set; }
[Parameter] public bool IsGridEditable { get; set; }
[CascadingParameter(Name = "ViewClient")]
public IViewClient? ViewClient { get; set; }
[Parameter] public string FlexStyling { get; set; }
}
IsGridCell tells the component that it is rendering inside a grid cell. Use it when the grid version must omit standalone content such as a label. IsGridEditable identifies whether the grid is editable. ContextIVMClassObject, binding information, rendering-action information, and the cascading ViewClient provide the MDriven context available to the component.
Register and deploy the component
- Add a project reference from the Blazor application to the Razor component library that produces the component assembly.
- Build the application. The component assembly is created in the build output.
- Include the files created under
wwwroot/_framework. A publish may be required to create all required files. Include both the WebAssembly file and its.wasm.gzfile. - Add
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>to the application project when you need resolved NuGet dependencies copied to the regular build output. - Copy the component files into the Turnkey application's
EXT_ComponentsRazorfolder. This folder is also scanned for*.jsand*.cssfiles, which are referenced early by the Blazor index page. - In MDriven Designer, set the
Blazor_Ext_Componenttagged value on the ViewModelColumn where the component must be rooted. Set its value in this format:AssemblyNameWithoutExtension;AdditionalAssemblyIfNeededWithoutExtension;AsManyAssembliesAsNeededWithoutExtension;TheTypeOfTheComponent. - Open the Blazor page and check the browser console for component-loading issues.
During development, set EXT_ComponentsRazorPath on MDrivenServerOverride to search additional component folders. Separate multiple paths with semicolons. For component scripts, set EXT_ComponentsRazorPathForJSScripts; at runtime, scripts are searched for under ./EXT_ComponentsRazor/CompName/script1.razor.js, with the same convention for js.map, ts, and css files.
Design for grids
The Blazor DataGrid uses QuickGrid with filtering and row virtualization enabled. Set --quickgrid-row-height to the row size, for example 30px, and make the CSS row height match. A mismatch can cause QuickGrid flicker. When your component can render both in a grid and standalone, use IsGridCell to apply the grid-specific markup and styling.
See also
Start using client-side Blazor
Start using client-side Blazor
You can test the client-side Blazor user interface by changing an existing AngularJS URL to use the Appl controller.
Test the Blazor client
- Start with an AngularJS URL, for example:
http://localhost:5020/App#/SeekerThings/$null$. - Change
App#toAppl. - Open the resulting URL:
http://localhost:5020/Appl/SeekerThings/$null$.
The documentation identifies appl as the controller for client-side Blazor.
Server-side Blazor
Server-side Blazor is supported with the appli route. For example: http://localhost:5020/Appli/SeekerThings/$null$.
Custom components
Custom components are not required for the initial URL test. The component guide describes adding components to specific tagged ViewModelColumns. Components for this framework must be built as Blazor WebAssembly components.
See Add custom Blazor components for the component requirements and build-output handling.
See also
Configure QuickGrid row height
Configure QuickGrid row height
You can prevent flickering in Blazor DataGrid views by making the QuickGrid row-height CSS variable match the height that your CSS renders for each row.
The Blazor DataGrid is based on QuickGrid and adds filtering. QuickGrid row virtualization is enabled, so it uses an item size to calculate which rows to render. Set that item size with the --quickgrid-row-height CSS variable.
Set the item size
Add the CSS variable to the CSS that applies to the grid. This example sets the QuickGrid item size to 30px:
--quickgrid-row-height: 30px;
Make the rendered row height match
Your row CSS must render rows at the height QuickGrid expects. A mismatch between --quickgrid-row-height and the actual rendered row height can make QuickGrid flicker while it virtualizes rows.
For example, if your grid CSS renders rows at 28px, use the matching value:
--quickgrid-row-height: 28px;
The documented default row height is 28px. If you change padding, borders, font sizing, or another CSS rule that changes the final row height, update --quickgrid-row-height to the resulting row height as well.
Verify the grid
- Open a Blazor view that contains a DataGrid.
- Scroll through enough rows for QuickGrid virtualization to load and replace rows.
- If rows flicker, compare the final rendered row height with
--quickgrid-row-height. - Adjust the variable or the row CSS until both heights are the same.
See also
Blazor component development
Blazor component development
You can extend a Turnkey Blazor UI with field-specific components and supporting scripts when you build custom UI for ViewModels.
Architecture overview
Turnkey renders a ViewModel in the browser through the Blazor UI engine. The standard Blazor UI renders the ViewModel, while a custom component can take over rendering for one tagged ViewModel column.
Use a column-specific component when, for example, one field needs a specialized editor or visualization and the other fields should retain the standard Blazor controls. To replace standard components broadly, use the broker described in Documentation:Blazor IComponentTypeSwitchBroker instead of assigning a component to each column.
Built-in components and extension API
The documented component API is the parameter contract for a custom component hosted by Turnkey. Build the component as a Blazor WebAssembly component. You can inherit MDCompBase through a reference to MDriven.Components.WebAssembly, or declare the required parameters in the component.
| Parameter | Purpose in the component contract |
|---|---|
CompType
|
The component type. |
XElement
|
XML information supplied to the component. |
BindInfoColumn and BindInfoNesting
|
Binding information for the ViewModel column and its nesting. |
ContextIVMClassObject
|
The current ViewModel object context. |
RendersAction and RendersActionThatUseAbstractAction
|
Action-rendering information. |
IsGridCell and IsGridEditable
|
Whether the component is rendering in an editable grid cell. |
ViewClient
|
The cascading parameter named ViewClient.
|
FlexStyling
|
Flex styling information. |
For a grid-cell component, use IsGridCell to distinguish the grid rendering from standalone rendering. A grid cell can avoid rendering a label that the standalone version would render.
Customization and hooks
Assign the Blazor_Ext_Component tagged value to the ViewModel column where the component must render. The tagged-value value has this form:
AssemblyNameWithoutExtension;AdditionalAssemblyIfNeededWithoutExtension;AsManyAssembliesAsNeededWithoutExtension;TheTypeOfTheComponent
Build output must be available to the Turnkey application. Copy the component files to EXT_ComponentsRazor. The component assembly is used for server-side Blazor, while the WebAssembly output is used by client-side Blazor. Include the compressed WebAssembly files so the client can request the appropriate download.
For development, configure EXT_ComponentsRazorPath on MDrivenServerOverride to search additional component paths. Separate multiple paths with semicolons.
For the required project setup, component parameters, output files, and tagged-value configuration, see Documentation:EXT ComponentsBlazor.
JavaScript interop
You can ship component-specific JavaScript with a Razor component. Place scripts where Turnkey can find them by using the runtime location:
./EXT_ComponentsRazor/CompName/script1.razor.js
Turnkey scans EXT_ComponentsRazor for *.js and *.css files and references them early in the Blazor index-page load process. During development, set EXT_ComponentsRazorPathForJSScripts to one or more semicolon-separated script paths. Turnkey also looks for related .js.map, .ts, and .css files in that development path.
Known limits and operational notes
- You cannot switch a single ViewModel between AngularJS and Blazor. Select the UI engine at the application level and test ViewModels that use framework-specific custom components before making Blazor the default.
- Registration and login remain server-side account-controller operations. Do not implement them as client-side ViewModel actions.
- The Blazor DataGrid uses QuickGrid with filtering and row virtualization. Its configured
--quickgrid-row-heightmust match the CSS-rendered row height. The default is 28 pixels; a mismatch can cause flickering while scrolling. - Use StringFormat on a ViewModel column for text formatting in Blazor.
Changelog
| Date | Change |
|---|---|
| September 2025 | The Blazor DataGrid uses QuickGrid with filtering and enabled row virtualization. Configure --quickgrid-row-height when CSS changes the rendered row height.
|
| July 2025 | Server-side Blazor is available through the Appli controller.
|
| September 2024 | Older server-side Blazor implementations were deprecated. Client-side Blazor is available through the Appl controller.
|
