Opx.MudBlazor.FlatUi 2.1.45

dotnet add package Opx.MudBlazor.FlatUi --version 2.1.45
                    
NuGet\Install-Package Opx.MudBlazor.FlatUi -Version 2.1.45
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Opx.MudBlazor.FlatUi" Version="2.1.45" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Opx.MudBlazor.FlatUi" Version="2.1.45" />
                    
Directory.Packages.props
<PackageReference Include="Opx.MudBlazor.FlatUi" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Opx.MudBlazor.FlatUi --version 2.1.45
                    
#r "nuget: Opx.MudBlazor.FlatUi, 2.1.45"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Opx.MudBlazor.FlatUi@2.1.45
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Opx.MudBlazor.FlatUi&version=2.1.45
                    
Install as a Cake Addin
#tool nuget:?package=Opx.MudBlazor.FlatUi&version=2.1.45
                    
Install as a Cake Tool

Opx.MudBlazor.FlatUi

Shared PDF printing: IFlatPrintService, Web desktop/mobile adapter and Android/Windows sample adapters. Print authorized PDF bytes through the existing viewer OnPrint callback; Submitted is distinct from confirmed completion. Native and physical-printer validation remain separate.

Mobile reliability P0–P2: unified refresh mode, scroll restoration, startup validation, cancellable latest-search, keyboard-aware CRUD and development-only diagnostics. Shared demo: /experience-toolkit.

See P0 compatibility and lifecycle gates for exact-package tests, live Web circuit regressions and native validation boundaries.

P1/P2 productivity adds unified saved views, guarded company/branch/site selection, nested filters, record workspaces and per-record bulk progress. Try the shared /enterprise-toolkit demo; persistence, authorization and business execution remain host-owned.

See Multipurpose operational toolkit for reusable ERP/HR/IoT work inbox, freshness, scan, telemetry, record relationships and personal-workspace composition, including native/backend ownership and validation boundaries.

Global panel-header sizing: set OpxFlatUi:Display:PanelHeaderMinHeight to 48 and PanelHeaderPaddingY to 10 (pixels; defaults). Headers may grow for subtitles/actions. See display settings.

Copyright © 2026 opx. All rights reserved.

Opx.MudBlazor.FlatUi is a reusable Razor Class Library for Blazor Web and MAUI Blazor Hybrid projects. It provides Fluent-like colors, compact page spacing, responsive application shells, mobile-first grid cards, bottom-sheet filters, paging, CRUD editor shells, safe-area-aware mobile dialogs, and consistent empty/detail/stat components.

Repository development guidance is available under .agents. Agents creating pages or reusable controls must follow the repo-local skill and use samples/Opx.MudBlazor.FlatUi.Showcase as the shared behavioral source of truth. The Web and MAUI sample hosts both load that assembly and its navigation catalog; native adapters remain MAUI-specific.

The template is intentionally multi-purpose. It can be used for ERP/business operations, IT operations, ecommerce/admin back offices, blogs/content sites, front pages, landing pages, dashboards, monitoring consoles, and reporting portals without locking the reusable components to one business domain.

Reporting controls include grouped operational reports, a typed responsive Pivot Grid, and FlatPdfViewer with packaged Mozilla PDF.js rendering, search, thumbnails, zoom, built-in Web print, and host-overridable native print/share/open callbacks. The /pivot showroom demonstrates runtime row/column dimensions, measure selection, five aggregate operations, totals, and exact-cell drill-down with copy-ready Razor usage; /pdf-viewer demonstrates the responsive document surface. The /enterprise-toolkit showroom covers 1.2-1.5, /experience-toolkit covers the 1.6-1.9 application experience APIs, and /operations-workspace demonstrates the 2.0 operational compositions.

Release line

The current source line is 2.1.x: 1.1-1.5 established the enterprise component foundation; 1.6-2.0 added accessibility, command, schema, collaboration, conflict, and operational compositions. Version 2.1 adds unified overlay/Back coordination, transaction validation, result-based editable-grid mutations, enterprise data/offline/native capability contracts, and a release-quality dashboard. See the roadmap, 2.1 contracts, application experience guide, and global application guide.

Preview

Web themes

Light Dark / Night
Opx MudBlazor Flat UI Light Web dashboard Opx MudBlazor Flat UI Dark Web dashboard

Mobile Web

<img src="docs/images/preview-mobile.png" width="390" alt="Opx MudBlazor Flat UI mobile CRUD preview" />

Settings

Settings provides live preview for Light, Dark/Night, and Auto themes; Vertical, Horizontal, and Bottom navigation; Bottom child presentation (Sheet or icon-and-text MainView); color palette; interface density; font size; and backdrop opacity. Its modal owns the resolved semantic surface tokens independently from the shell: Light keeps neutral/white panel surfaces while the selected palette colors only accent selection and interaction states. Font size scales text globally across the shell, navigation, pages, grids, dialogs, menus, Settings, and reusable components while leaving icons and the selected spacing preset unchanged. Save persists the browser preference, Cancel restores the previously applied values, and Restore application defaults returns to the host configuration. FlatDisplaySettingsConfiguration can select, reorder, lock, localize, or template individual sections; IndonesianEssentials provides the focused Tema, Palet warna, Ukuran font, and Target sentuh surface. See Composable display settings.

Opx MudBlazor Flat UI application settings

Install into a host app

An executable Android/Windows MAUI Blazor Hybrid reference is available at samples/Opx.MudBlazor.FlatUi.MauiHost.Sample. It shows the root session gate, typed configuration, Debug/Release asset selection, viewport-only Bottom/Sidebar navigation, and host-owned native adapter boundaries. The project defaults to a source ProjectReference; consumers can switch its documented UseFlatUiProjectReference property off to validate the matching NuGet package.

  1. Reference the package/project and MudBlazor.

  2. In _Imports.razor:

    @using Opx.MudBlazor.FlatUi
    @using Opx.MudBlazor.FlatUi.Components
    @using Opx.MudBlazor.FlatUi.Components.Grid
    @using Opx.MudBlazor.FlatUi.Models
    @using Opx.MudBlazor.FlatUi.Services
    
  3. In the host HTML/head, keep the stylesheet static and resolve the JavaScript from FlatAssetOptions. Debug always uses the readable source; Release defaults to the generated minified asset.

    <link href="_content/Opx.MudBlazor.FlatUi/opx-flat-ui.css" rel="stylesheet" />
    <script src="@AssetOptions.ResolveJavaScriptPath(IsDebugBuild)"></script>
    
    @code {
        [Inject] private FlatAssetOptions AssetOptions { get; set; } = new();
    
    #if DEBUG
        private const bool IsDebugBuild = true;
    #else
        private const bool IsDebugBuild = false;
    #endif
    }
    
  4. Wrap the app layout with FlatMudProviders or put equivalent MudBlazor providers in the host. If the host restores a saved session, mount an interactive root startup gate before Router; keep FlatSessionRestore inside those providers while blocked, and construct Router only after the host check succeeds. This applies to anonymous routes such as Login too.

  5. Register application branding and display preferences. Application defaults come from configuration; each user/browser display override is stored in localStorage and survives navigation/reload without modifying the server configuration file.

    var applicationOptions = builder.Configuration
        .GetSection("OpxFlatUi:Application")
        .Get<FlatApplicationOptions>() ?? new FlatApplicationOptions();
    builder.Services.AddSingleton(applicationOptions);
    
    var displayOptions = builder.Configuration
        .GetSection("OpxFlatUi:Display")
        .Get<FlatUiDisplayOptions>() ?? new FlatUiDisplayOptions();
    builder.Services.AddSingleton(displayOptions);
    builder.Services.AddScoped<FlatUiPreferencesService>();
    
    var reconnectOptions = builder.Configuration
        .GetSection("OpxFlatUi:Reconnect")
        .Get<FlatReconnectOptions>() ?? new FlatReconnectOptions();
    builder.Services.AddSingleton(reconnectOptions);
    
    var gridOptions = builder.Configuration
        .GetSection("OpxFlatUi:Grid")
        .Get<FlatGridOptions>() ?? new FlatGridOptions();
    builder.Services.AddSingleton(gridOptions);
    
    var loadingOptions = builder.Configuration
        .GetSection("OpxFlatUi:Loading")
        .Get<FlatLoadingOptions>() ?? new FlatLoadingOptions();
    builder.Services.AddSingleton(loadingOptions);
    
    var assetOptions = builder.Configuration
        .GetSection("OpxFlatUi:Assets")
        .Get<FlatAssetOptions>() ?? new FlatAssetOptions();
    builder.Services.AddSingleton(assetOptions);
    

    Initial appsettings.json

    Use this baseline for a new Web or MAUI Hybrid host, then change only the values the application intentionally owns. The global grid default is a compact searchable header with search/sort affordances and no metadata/type icons; individual grids can still override both settings.

    {
      "OpxFlatUi": {
        "Localization": {
          "Culture": "en-US",
          "UiCulture": "en-US",
          "TimeZone": "Asia/Jakarta",
          "DateFormat": "dd MMM yyyy",
          "DateTimeFormat": "dd MMM yyyy HH:mm",
          "Currency": "IDR",
          "RightToLeft": false
        },
        "Assets": {
          "UseMinifiedJavaScript": true
        },
        "Application": {
          "AppName": "OPX Flat UI",
          "CompanyName": "OPX",
          "Logo": null,
          "Copyright": "© {Year} {CompanyName}",
          "LoginBrandBackgroundColor": "#5274b9",
          "LoginBrandBackgroundImageUrl": null,
          "LoginBrandPanelVisible": true,
          "LoginBrandOverlayColor": "#000000",
          "LoginBrandOverlayOpacity": 0.0,
          "LoginLayout": "Default"
        },
        "Grid": {
          "DefaultPageSize": 15,
          "PageSizes": [10, 15, 25, 50, 100],
          "DefaultHeaderStyle": "CompactSearch",
          "ShowHeaderIcons": false
        },
        "Loading": {
          "InitialSkeletonEnabled": true,
          "DefaultTemplate": "Auto",
          "DataGridColumnCount": 5,
          "RowCount": 8,
          "MobileRowCount": 6,
          "MobileFieldCount": 4
        },
        "Snackbar": {
          "HideTransitionDurationMs": 200
        },
        "Reconnect": {
          "StartupTitle": "Loading page...",
          "StartupMessage": "Please wait a moment.",
          "ReconnectingTitle": "Rejoining the server...",
          "ReconnectingMessage": "Please wait a moment.",
          "PausedTitle": "Connection paused",
          "PausedMessage": "The app will resume automatically.",
          "FailedTitle": "Connection lost",
          "FailedMessage": "Check the network, then try again.",
          "RetryText": "Try again"
        },
        "DeviceNotification": {
          "SampleTitle": "OPX Flat UI",
          "SampleMessage": "This notification is delivered through the local device notification system.",
          "SampleTag": "opx-flat-ui-sample"
        },
        "Display": {
          "AppBarSearchVisible": true,
          "DefaultFabShape": "Circle",
          "DefaultRoundedSizePx": 0,
          "HostKind": "Web",
          "DefaultThemeMode": "Auto",
          "DefaultDensity": "Default",
          "DefaultInputStyle": "Outlined",
          "DefaultNavigationLayout": "Vertical",
          "DefaultBottomNavigationChildPresentation": "Sheet",
          "DefaultColorPalette": "blue",
          "UseAppFontSize": false,
          "DefaultFontSizePx": 16,
          "MinimumFontSizePx": 12,
          "MaximumFontSizePx": 18,
          "DefaultBackdropOpacity": 0.48,
          "MinimumBackdropOpacity": 0.30,
          "MaximumBackdropOpacity": 0.80,
          "AutoScaleHighDensityTouchButtons": true,
          "HighDensityTouchButtonHeightPx": 42,
          "HighDensityTouchFloatingLabelFontSizePx": 12.5,
          "SidebarGroupFontWeight": 400,
          "SidebarItemFontWeight": 400,
          "LightSidebarBackground": "#f3f6f9",
          "LightSidebarForeground": "#495057",
          "DarkSidebarBackground": "#212529",
          "DarkSidebarForeground": "#ced4da",
          "StorageKey": "opx.flat-ui.display"
        }
      }
    }
    

    Sidebar menu colors start from host defaults in appsettings and are also available in Settings for per-user live preview and persistence. Set LightSidebarBackground, LightSidebarForeground, DarkSidebarBackground, and DarkSidebarForeground under OpxFlatUi:Display using six-digit hex values. Empty, whitespace, null, invalid settings, or invalid saved overrides fall back independently to the normalized host value, then to #f3f6f9 / #495057 in Light and #212529 / #ced4da in Dark/Night. Cancel restores the saved values and Restore application defaults returns all four values to appsettings. They affect the drawer/menu surface and ordinary menu text/icons, while hover and active states retain their semantic accent treatment; keep text contrast at least 4.5:1.

    The NuGet package contains both opx-flat-ui.js and opx-flat-ui.min.js. The readable file remains the development source; Release/Pack generates the minified file from the pinned build toolchain. See JavaScript asset pipeline.

Component usage examples

Responsive page, toolbar actions, pull-to-refresh, and FAB

FlatPage owns proportional page/panel spacing. Configure a standard CRUD create action once; it automatically renders a Filled desktop button above 900px and an icon-only FlatFab at 900px and below. Data actions remain icon-only in the toolbar.

The source after 2.1.20 also accepts optional Title="..." for compatibility. A nonblank title labels the page root as an accessible region; it does not render a duplicate heading, change the browser document title, or override the host AppBar PageTitle. Null/blank leaves the existing unlabeled wrapper unchanged. Consumers must upgrade to a package containing this addition before passing Title; older packages reject it during parameter binding.

Bind the page's first empty request to InitialLoading; FlatPage automatically chooses grid, form, dashboard, or list/detail skeleton geometry from FlatPageKind. SkeletonTemplate, count parameters, and LoadingContent provide per-page customization. Do not set InitialLoading for later refresh/filter/sort/paging/CRUD reloads; preserve established content and use FlatPageLoadingState for the AppBar line.

<FlatPage Kind="FlatPageKind.Module"
          RefreshEnabled="true"
          OnRefresh="LoadAsync"
          ExportVisible="true"
          OnExport="ExportAsync"
          PullToRefreshEnabled="true"
          NativePullToRefreshEnabled="true"
          PrimaryActionVisible="true"
          PrimaryActionLabel="Add"
          PrimaryActionIcon="@Icons.Material.Outlined.Add"
          PrimaryActionAriaLabel="Add record"
          OnPrimaryAction="OpenCreate">
    <ToolbarContent>
        <MudTextField @bind-Value="_search"
                      Placeholder="Search records..."
                      Variant="Variant.Outlined"
                      Margin="Margin.Dense" />
    </ToolbarContent>

    <ChildContent>
        <FlatDataGrid TItem="AssetRow"
                      State="_gridState"
                      Columns="_columns"
                      Items="_rows"
                      ExportVisible="true"
                      ExcelFileName="asset-view.xlsx"
                      RowTemplate="RenderRow" />
    </ChildContent>
</FlatPage>

When FlatDataGrid.ExportVisible is enabled without an OnExport callback, the grid generates and downloads a native .xlsx workbook containing its visible columns in rendered order and the localized values of its materialized rows. ExcelExportItems can supply the complete already-filtered/sorted view instead of the displayed page. Existing OnExport remains the server/virtualized/large-dataset override. See Data-grid Excel export.

Enable PullToRefreshEnabled only on eligible Web data/feed pages and always provide a real OnRefresh handler. Dashboard/DashboardList are the default-enabled exception when that handler exists; set DashboardPullToRefreshEnabled="false" to opt out. FlatPage automatically recognizes its primary .mobile-grid-list; set PullToRefreshScrollSelector when a page owns a different primary mobile scroll region. The gesture begins only when that owner and the document are at the top. A mounted CrudEditorShell suspends Web/native pull-to-refresh and closing it restores the underlying page state.

Inside FlatAppShell HostKind="FlatUiHostKind.MauiHybrid", NativePullToRefreshEnabled="true" registers the same callback with the Android/Windows host RefreshView. The MAUI host must register singleton FlatNativePullToRefreshState, wrap its persistent BlazorWebView, bind IsRefreshEnabled, and dispatch with TryDispatchAsync. Native mode takes precedence over the JavaScript gesture when both flags are true. An active gesture suppresses duplicate page and nested report/PDF Refresh actions; without a real handler the button remains. Web ignores the native flag and keeps its package gesture behavior.

Responsive CRUD form modal

The same component renders centered on desktop/wide tablet and fullscreen on mobile. Browser Back closes the active modal before navigating the page.

<FlatFormModal @bind-Open="_editorOpen"
               Title="Edit record"
               Mode="Update"
               IsDirty="_dirty"
               CanSubmit="@IsValid"
               CloseOnOutsideClick="false"
               ConfirmClose="ConfirmDiscardAsync"
               SubmitHandler="SaveAsync"
               OnResult="HandleModalResult"
               AutoRefreshOnSuccess="true"
               OnRefreshRequested="ReloadPageAsync">
    <div class="flat-crud-form-grid">
        <MudTextField @bind-Value="_model.Code"
                      Label="Code"
                      Variant="Variant.Outlined"
                      Margin="Margin.Dense" />
        <MudTextField @bind-Value="_model.Name"
                      Label="Name"
                      Variant="Variant.Outlined"
                      Margin="Margin.Dense" />
    </div>
</FlatFormModal>

Back, Cancel, and an enabled backdrop close return false through OnResult and never request a caller refresh. A submit returns true only after OnSubmit or SubmitHandler completes successfully. FlatFormModal is CRUD-oriented, so AutoRefreshOnSuccess defaults to true; when OnRefreshRequested is supplied it invokes the caller's existing load pipeline after a successful close without hard-reloading the browser or resetting query/filter/paging state. Set AutoRefreshOnSuccess="false" for non-CRUD forms.

Searchable combo box

<FlatSearchComboBox T="string"
                    Label="Department"
                    Items="_departments"
                    @bind-Value="_departmentId" />

@code {
    private string? _departmentId;

    private readonly IReadOnlyList<FlatSearchComboOption<string>> _departments =
    [
        new("FIN", "Finance") { Description = "Accounting and treasury" },
        new("HR", "Human Resources") { Keywords = "people employees" },
        new("OPS", "Operations")
    ];
}

For API-backed lookup, supply the cancellable SearchAsync delegate instead of loading an unbounded option list.

Shared message box

Register FlatMessageBoxService, inject it into the page, and call the semantic helper rather than duplicating dialog markup.

@inject FlatMessageBoxService MessageBox

@code {
    private async Task DeleteAsync()
    {
        var confirmed = await MessageBox.QuestionAsync(
            "Delete the selected record?",
            title: "Delete record",
            confirmText: "Delete");

        if (!confirmed)
            return;

        // Call the authorized application service here.
    }
}

Documentation

  • Migration to 2.1

  • Official release roadmap: delivered release history, the active 2.1.7 gate, and the ordered ERP release train.

  • Migration from 1.0.x to 1.1.0: opt-in APIs, ownership boundaries, compatibility notes, and validation.

  • Message box: reusable reference-aligned question, warning, information, and error prompts.

  • Processing state: reusable page/form disabled state, loading backdrop, cancellation, and lifecycle callbacks.

  • Documentation index

  • NuGet publishing: safe PackOnly default, explicit -Publish, automatic patch/minor/major version increment, package validation, and secure API-key handling.

  • Multi-select component: reusable option model, permission-style example, and theming hooks.

  • Search combo box: searchable single-value combo with local options or a cancellable async/API provider.

  • ERP sample pages: route matrix, UX architecture, responsive behavior, extension workflow, real-service integration guidance, and validation checklist.

  • Authentication and navigation templates: login, two-step verification, vertical/horizontal navigation, configuration, responsive fallback, and security boundaries.

  • Sidebar typography: appsettings-backed group and leaf font weights, defaults, normalization, and host integration.

Design contracts

  • Responsive design is adaptive, not a scaled desktop. OPX retains its established 900px table/card boundary, 601-900px two-card range, 600px phone refinement, device/browser 1rem default, optional app-controlled 16px baseline, density presets, and high-density touch settings. Use shared tokens and viewport/container CSS—not Android/iOS detection or page-local type scales—to adapt navigation, hierarchy, forms, actions, and information density. Mobile prioritizes readable primary content, touch geometry, one-column forms, and equivalent shared-state cards/lists; desktop remains compact, multi-column, and data-oriented. Validate desktop, responsive/tablet, phone, and no-reload live resize in Light/Dark/Auto; native MAUI behavior still needs device/emulator evidence. See Responsive design.
  • Treat viewport and host capability independently: breakpoints choose Web/MAUI/Windows mobile, tablet, or desktop composition; FlatUiHostKind changes only genuine host integrations such as native gestures, notifications, status/safe-area handling, file/camera, system Back, print/share/open, and lifecycle. A narrow Web viewport is not automatically a native device, and a wide MAUI window still retains its native host capabilities.
  • Desktop/wide tablet CRUD forms are centered/panel based; mobile forms are always fullscreen with visible close/back actions. This mobile modal geometry is owned by the shared editor and is independent from page FAB/no-FAB spacing. CrudEditorShell.CloseOnOutsideClick controls backdrop dismissal and defaults to false: use true for click-anywhere/backdrop close, or keep false when closing must go through Back/Cancel. While an editor is open, a same-URL history guard consumes the first browser Back action, including for a clean form; the same close guard then handles processing and dirty confirmation. A rejected close re-arms the guard and keeps the modal and route unchanged. Visible Back/Cancel removes the guard without adding a phantom Back step.
  • CRUD editor forms use compact Margin.Dense controls and the reusable .flat-crud-form-grid: two columns with a 10px column gap and 7px row gap on desktop/tablet, then one column with a 6px row gap at 600px and below. Direct editor-body children use a 7px vertical gap. Direct field margins are normalized to 4px 0 0, editor body padding is 14px 16px, and helper/error text may add only the height it actually needs. Fullscreen mobile editor space stays below the top-aligned form; it never stretches grid rows or input controls to fill the viewport. Editor headers use a 54px desktop/wide-tablet minimum, a 56px mobile minimum before safe-area expansion, and a compact 2px mode-to-title gap while retaining the Back button touch target.
  • Save/update/delete operations use the shared processing contract. DisableContent locks all descendant controls; Backdrop adds a theme-synchronized blocking overlay and progress indicator. Prefer cancellable SubmitHandler/RunAsync operations and use completion, cancellation, and failure callbacks; always restore interaction in every success, failure, and cancellation path.
  • Mobile page gutters are equal: top panel gap, left gutter, and right gutter default to 16px.
  • Internal component rhythm is compact: keep panel/card/filter spacing tight, while preserving the outer 16px mobile gutters.
  • AppBar terminology is fixed: row 1 is AppName, row 2 remains PageTitle. Do not rename the second row to AppTitle, and do not leave PageTitle static when navigation changes. AppName is compact and bold for brand recognition; PageTitle is compact and regular so the title block does not dominate the toolbar. At the app-controlled 16px baseline they resolve to approximately 12px and 11px, and density presets preserve those ratios.
  • AppBar page titles are normalized for readability: route/module tokens such as Operations-CrudAsset render as Operations - Crud Asset.
  • Keep reusable component naming, defaults, and layout contracts domain-neutral. Domain wording such as IT, ecommerce, retail, landing, or operations belongs in the consumer app/sample data, not in shared component internals.
  • New operational pages default to no visible description/intro heading. Rely on the AppBar page title and show only the content panel/grid/form; add visible explanatory copy only when intentionally requested. Use FlatPageHeading only for optional explicit descriptions/actions, so placeholder blocks like CRUD / Asset Management / Contoh grid... are not created by default.
  • Hamburger/drawer behavior follows the reference Hybrid shell: drawer starts closed until breakpoint is known, hamburger is visible on desktop and mobile, desktop toggles layout offset without leaving stale margin, and mobile/tablet opens an overlay drawer that closes after navigation or after clicking/tapping anywhere outside it. Interactions inside the drawer do not dismiss it.
  • On responsive/mobile AppBar, the hamburger button is intentionally closer to the left edge so the icon visually aligns with the 16px content gutter.
  • AppBar settings/overflow action uses a three-dot icon (MoreVert), not a gear, unless the page opens a dedicated settings screen.
  • AppBar device-notification and settings/overflow actions are borderless, shadowless icon buttons whose normal surface matches the AppBar. Hover, focus, active, and open states use a slightly raised theme color so interaction remains visible.
  • MudBlazor button states remain visibly distinct on mobile and desktop. Standard/Default, Primary, Secondary, Tertiary, Info, Success, Warning, Error, and Dark use a strong family color while enabled; disabled Filled, Outlined, and Text variants use a quieter desaturated family tint, border, and foreground in both Light and Dark/Night. Disabled state keeps native semantics and no shadow, and does not rely only on cursor or one global opacity.
  • Default MudBlazor checkboxes use the active accent when checked/indeterminate, a readable theme-aware outline when unchecked, and normal foreground label text. Disabled checkbox glyphs and labels are deliberately quieter in Light and Dark/Night, while the checkbox icon surface stays transparent and explicit semantic checkbox colors remain available.
  • High-density mobile touch devices automatically increase ordinary text buttons to a configurable touch target (default 42px) and edit-form floating labels to a readable caption size (default 12.5px). Detection combines a mobile viewport, coarse/touch input, and at least 1.75dppx, so a 4K desktop with a mouse is not enlarged accidentally. Configure OpxFlatUi:Display:AutoScaleHighDensityTouchButtons, HighDensityTouchButtonHeightPx (38-52px), and HighDensityTouchFloatingLabelFontSizePx (11.5-15px); specialized FAB, compact icon-toolbar, input adornment geometry, empty placeholder-like labels, field height, and form gaps remain independent.
  • Sidebar search updates the menu tree immediately with case-insensitive matching, auto-expands matching parent groups, hides unrelated groups/items, shows an empty state when no item matches, and restores the full tree when cleared. Split sidebar/menu components must propagate a new cascading search-state snapshot (or an equivalent explicit change notification) for every query update.
  • Sidebar search keeps a compact 30px input with 4px vertical breathing room inside a 38px wrapper; this spacing applies consistently on desktop and overlay drawers without changing menu indentation.
  • Sidebar search placeholder text is intentionally compact and regular weight (10-11px, weight 400). This navigation-specific style is scoped to the sidebar and does not change AppBar search or form placeholders.
  • Blocking backdrops lock scrolling and interaction on the underlying page for overlay drawers, settings/about, CRUD/form editors, bottom sheets/filters, and dialogs. Backdrop opacity is configurable from OpxFlatUi:Display and the Settings live-preview slider, then follows the same Save, Cancel, Restore, and browser-persistence contract as other display preferences.
  • Confirmation/message boxes require an explicit visible action: Question closes through Confirm or Cancel; Warning, Information, and Error close through their acknowledgement button. Backdrop click, Escape, and route navigation do not dismiss the prompt; each variant uses its semantic color, and Dark/Night keeps the title and outlined Cancel label at readable contrast.
  • AppBar page/component search is a host-supplied navigation autocomplete. Pass FlatNavigationSearchItem entries through FlatAppShell.SearchItems; focus shows menu choices, typing matches title/group/keywords, Arrow Up/Down changes the active choice, Enter navigates, Escape closes, and an unmatched query shows an English empty state. Set FlatAppShell.SearchVisible="false" to remove the search and its focus target completely. Hosts may bind this to OpxFlatUi:Display:AppBarSearchVisible, which defaults to true for compatibility. Keep domain routes and keywords in the consumer host, not in the reusable library.
  • The AppBar settings/overflow menu should use the dot-3 icon as a top-level overflow list that can contain Settings and other app menus. Settings opens a dedicated settings form modal, not an inline dropdown; desktop is centered and mobile is fullscreen/safe-area aware. Theme choices belong under Theme settings: Light, Dark / Night, and Auto. Auto follows the device/system preference on the first paint and on later system-theme changes; load opx-flat-ui-theme-bootstrap.js in <head> before theme stylesheets and bind its storage/default attributes as documented in Theme startup and Auto mode.
  • AppBar overflow menu labels use the active foreground token at full opacity. In Dark/Night mode, enabled labels use #ced4da and may increase to white on hover/focus; only genuinely disabled items use reduced contrast.
  • Dark/Night theme uses one consistent graphite hierarchy: workspace #1a1d21, surface/sidebar #212529, input/secondary surface #262a2f, hover #2a2d31, header/raised surface #292e32, border #32383e, primary text #ced4da, secondary text #878a99, and default filled Primary #005f91. Settings, AppBar menus, Kanban, Chat, dialogs, and portals share these tokens; legacy pure-black component islands are normalized away.
  • Light semantic theme tokens use primary #004a77, secondary #865ce2, success #13c56b, info #50c3e6, warning #e8bc52, and danger #ed5e5e. Use FlatColorReference or the /colors sample to inspect solid, subtle, border, emphasis, surface, and opacity variants under the active theme.
  • All MudBlazor controls must follow the active theme, including overlay/portal controls such as combo/select dropdowns, notification menus, menus, popovers, pickers, dialogs, list items, input adornments, hover, unread, and selected states. Dark mode must not leave a white menu body or item surface unless the page explicitly renders media/content that should stay light.
  • Dark/Night multi-select popovers keep their list on #212529; the optional Select All header is raised to #31363c with readable #e9ecef text and a #495057 divider.
  • Dark/Night combo/list selections use a palette-aware raised accent surface instead of the near-black hover color. Normal portal items use #ced4da, selected items use white, and the selected background remains visibly distinct from the #212529 list surface and #2a2d31 hover state.
  • Outlined combo/select wrappers remain transparent so label margins do not render as a larger background block. Apply the themed control surface only to the visible outlined input area; dropdown/popover surfaces still follow the active theme.
  • Textbox and textarea placeholders use a small relative 2px size increase and a subtle theme-specific secondary-text mix at full opacity: Light mixes 92% active secondary text with 8% white, while Dark/Night mixes it with 8% black. Native placeholders, empty/non-floating labels, floating labels, entered textbox/textarea values, and selected combo values all use normal 400 weight. Empty labels retain their minimum 13px size and 2px upward optical offset; CRUD values retain their responsive 12.5px scale. Typography continues to scale with display settings without changing input height or floating-label geometry.
  • MudBlazor outlined floating labels use one library-wide minimum formula of 11.5px before MudBlazor applies its 0.75 floating transform. The same baseline applies to textbox, textarea, select/combo, CRUD, account/settings, modal, desktop, tablet, and mobile fields; page-scoped reductions are not allowed. High-density mobile touch devices may raise only the floating caption to the configured HighDensityTouchFloatingLabelFontSizePx default of 12.5px. Compact forms use Margin.Dense so control height, value, adornment, validation geometry, and form gaps remain synchronized.
  • Browser autofill is theme-safe by default. Inputs, textareas, and selects keep the resolved Light, Dark/Night, or Auto field surface, text, and caret colors across autofill hover/focus/active states, including fields with transparent adornments. No page-specific Login CSS is required.
  • Outlined field containers use one continuous theme-resolved surface across value and adornment areas, including autofill. Adornment wrappers, glyphs, and clickable icon buttons stay transparent, borderless, and shadowless over that field surface, while standalone, AppBar, toolbar, and grid icon buttons retain their own interaction-state styling.
  • Desktop grid column headers use compact glyphs: 14px for sort and 15px for filter. Keep the filter button hit area at 24x24px with accessible labels and visible hover/focus/active states. The global default is FlatGridHeaderStyle.CompactSearch with ShowHeaderIcons=false, so search/sort remains available without metadata/type icons. Configure optional HeaderIcon and SearchPlaceholder on GridColumnDefinition; set component HeaderStyle or ShowHeaderIcons only for a deliberate local override, including Standard for the legacy filter-row presentation.
  • Desktop FlatDataGrid has one theme-synchronized two-axis scroll region. Excess rows show a vertical scrollbar and wide columns show a horizontal scrollbar, while the grid toolbar and pager remain fixed outside the scrolling body. A custom direct div host under .module-panel needs no special class: the package bounds it on desktop and hides it when the equivalent mobile grid is active. Opening a modal locks document scrolling without removing the internal grid scrollbar geometry. FlatDataGrid, FlatGroupedDataGrid, and FlatEditableGrid independently expose AlternatingRows (default false), ShowVerticalLines (default true), and ShowHorizontalLines (default true). AutoRowHeight defaults to false; enabling it wraps non-numeric content, grows each row to its tallest cell, and top-aligns the row while numbers stay single-line/right-aligned. Responsive cards keep their own record geometry and separators.
  • GridColumnDefinition accepts proportional WidthPercent or fixed WidthPx (fixed wins). Automatic cells infer public properties by column key; ValueSelector maps custom keys. Numeric/currency columns are right-aligned and formatted with OpxFlatUi:Localization, while custom templates receive FlatGridCellContext.FormattedValue. See API grid loading.
  • The /data-grid-large sample deliberately exercises both axes with 120 deterministic in-memory records, 12 columns, and a 50-row initial page. At 900px and below, the same filtered/paged records render as responsive cards without document-level horizontal overflow.
  • The AppBar notification action means a local OS/device notification, not a snackbar, dialog, or in-app notification-feed menu. Use FlatDeviceNotification with an IDeviceNotificationService host adapter; permission, scheduling, cancellation, tap routing, and native lifecycle remain platform-owned.
  • Sidebar tree menus (MudNavGroup) follow the reference shell behavior: search filters menu items, matching groups auto-expand, active routes expand their parent group, collapsed children are clipped, transitions are disabled for stable MAUI Hybrid rendering, and child indicators use dotted vertical/horizontal connectors aligned to the child-icon center axis.
  • Sidebar group and leaf labels both default to font weight 500 so a menu that owns children does not look inconsistently lighter than a normal item. Configure OpxFlatUi:Display:SidebarGroupFontWeight and SidebarItemFontWeight in appsettings when a host intentionally needs different hierarchy weights.
  • Sidebar parent and child links follow the reference geometry: root links use a 6px icon-to-text gap and every nested link uses a compact 2px gap. At every nesting depth, a child or sub-child icon aligns horizontally with the start of its immediate parent label—for example, ERP Overview aligns with ERP and HR Overview aligns with Human Resources. Each dotted connector ends 3px before its child icon. The menu tree and collapse wrappers fill their parent width, each nested collapse subtracts only its own indent, and the scroll region reserves a stable scrollbar gutter. Computed link width, padding, and icon/text coordinates remain stable when overflow appears, a deeper group opens, or a child becomes active.
  • Sidebar leaf links and group titles support FlatNavigationBadge for compact counts, text statuses, or labeled dots. Parent groups use TitleContent while retaining a plain Title for accessibility. Badges use semantic Light/Dark colors, truncate long values, and do not alter sidebar icon/text/connector/chevron geometry. See Authentication and navigation templates.
  • Blazor Server reconnect/rejoining UI follows the reference compact notice: #components-reconnect-modal.server-reconnect-notice, bottom-right on desktop, 12px side gutters on mobile, English status text, spinner while reconnecting, dot for paused/failed, and no blocking full-screen backdrop.
  • Web and MAUI host documents replace the built-in #blazor-error-ui message with a static, theme-safe OPX full-page recovery surface. It exposes no exception details or Dismiss action and offers one Restart action because a terminated circuit cannot safely continue.
  • Public frontend websites should use a dedicated website shell/layout instead of the admin drawer shell. Use it for landing pages, storefronts, blog/content pages, front pages, and campaign pages.
  • AppBar hamburger spacing must keep the icon close to the left edge while preserving a small breathing gap before the title block; current rule adds 2px more space between hamburger and title.
  • Include auth reference screens where applicable: login should be a standalone full-screen page, and logout should be reachable from the signed-in user block.
  • Login/auth password controls with show/hide use opx-password-visibility-field: the transparent eye/eye-off action is white in resolved Dark/Night and #212529 in resolved Light, and retains that contrast after toggling the input between password and text. Production hosts must retain an accessible label and keyboard action.
  • Two-step verification templates are UI workflow samples only. Use one-time-code input semantics, masked delivery targets, resend/back actions, and clear error/success states, but leave code generation, delivery, expiry, retry/rate limits, replay protection, trusted-device policy, recovery, and session issuance to the consumer authentication service.
  • Reset-password templates include reset-request, temporary-code, new-password, confirmation, requirement feedback, success, and back-to-login states. Keep passwords transient and clear code/password fields after completion; server-side token validation, expiry, rate limits, password policy, credential update, session revocation, and audit remain consumer responsibilities.
  • Admin navigation can be configured as Vertical, Horizontal, or Bottom. Horizontal is Web desktop-only and uses a compact module bar; tablet/mobile falls back to the reference drawer. Bottom is available on Web and MAUI Hybrid, activates only at phone widths, and falls back to the sidebar on tablet/desktop. It reuses the shared route tree, limits the bar to five equal-width roots, moves overflow into More, and opens parent children in a locked, recursive bottom sheet. Wherever Web global search is visible, the AppName/PageTitle block takes the rendered width of its wider line and the search border starts exactly 16px after that block; unusually long titles are capped and ellipsized. Layout changes preview immediately in Settings and persist through FlatUiPreferencesService.
  • AppBar global search renders one focus indicator on its composite wrapper. The inner text input remains transparent and does not add a second nested focus border; the wrapper ring remains visible in Light and Dark/Night.
  • Profile avatars should accept any image URL while still supporting configurable initials as fallback or intentional initials-only display.
  • Sample charts must use MudBlazor chart components (MudChart) instead of hand-drawn div/SVG bars, so chart behavior, legends, and responsive rendering follow MudBlazor. The /charts showroom renders all eleven chart types available in MudBlazor 9.7.0 and provides expandable copy-ready Razor samples; see MudBlazor chart showroom.
  • Do not show online/live/realtime indicators in the AppBar by default. Only pass RealtimeText when a consumer app has a real live connection state worth showing.
  • Standard CRUD primary actions use the FlatPage PrimaryAction* parameters and OnPrimaryAction; one declaration automatically creates the desktop Filled button and mobile icon-only FAB. Specialized manual mobile actions may still use FlatFab, which is hidden on desktop and fixed above the bottom safe-area. Keep the FAB visually flat with no shadow in normal, hover, focus, or active states; keyboard focus uses an outline instead.
  • FlatFab is icon-only by default. Keep text in AriaLabel/title for accessibility, but do not show a visible text label unless an explicit exception sets Extended=true.
  • Do not combine the automatic primary-action API with manual HeaderActions or MobilePrimaryAction for the same action. FlatPage owns responsive mutual exclusion and hides the complete inactive wrapper so mobile spacing is not reserved accidentally.
  • Grid/list pages without a mobile FAB must have root class no-mobile-fab and keep proportional mobile gutters: top 16px, left 16px, right 16px, bottom 16px. Pages with a FAB use has-mobile-fab, keep extra bottom padding so the FAB never covers content, and cap the grid/panel scroll area between the top content gutter and the top of the FAB with at least 16px clearance.
  • Responsive record cards keep their outer boundary 1px solid, while dividers inside the same record use 1px dotted for the header, fact rows/columns, references, progress, and action footer. The final internal divider is removed where it would duplicate the solid outer boundary.
  • Grid sizing must be verified proportionally, not by source inspection only. On mobile, use computed layout values: top/left/right page gutters 16px, no-FAB bottom 16px, FAB bottom reserve, panel left/right gutter equal against document.documentElement.clientWidth, bounded panel height around 88vh/88dvh, and internal scrolling in the grid/list area.
  • Responsive cards use two fact columns from 601px through 900px. Keep the card/header/footer boundaries solid while internal fact-row and fact-column separators are dotted; at 600px and below return to the single-column mobile separator geometry.
  • Grid data actions belong in the grid/panel toolbar. Put Filter, Import, Export, Download CSV, Print, and Refresh in FilterEnabled, ToolbarActions, RefreshEnabled, or a .module-toolbar directly above the grid; do not place them in the page heading/AppBar/hero action area. Keep these toolbar actions icon-only, inline, and one row, with text only in aria-label/title.
  • Operational grid/list pages must not reserve a BeforePanel or .page-actions-only row for data actions. A writable page may expose one create action per viewport: a desktop action that is hidden at the responsive cutoff and an icon-only mobile FAB, never both at once. Read-only pages must not expose Add, Edit, Delete, or a create FAB.
  • ReadOnlySource is reserved for genuinely non-mutating samples. Do not apply the read-only marker to an in-memory CRUD sample that can add or edit records.
  • Built-in FlatPage toolbar actions are individually toggleable: FilterVisible/FilterEnabled, RefreshVisible/RefreshEnabled, ImportVisible, DownloadVisible, ExportVisible, and PrintVisible. Add custom extra buttons with ToolbarActions; custom buttons should use .grid-action-button and stay in the same one-line action row.
  • FlatPage hides its Filter action unless FilterVisible/FilterEnabled resolves to true and OnFilter has a real handler. Do not show a separate Filter icon for a grid that only has inline search or has no filter UI; enable it only when it opens an actionable filter sheet, panel, popover, or equivalent experience.
  • Default grid filtering is column-driven: use one GridColumnDefinition collection for desktop headers and the responsive filter sheet, and one GridViewState for current criteria. Derive toolbar Filter visibility from Columns.Any(column => column.FilterEnabled); never maintain separate mobile filter metadata or state.
  • On responsive/mobile grid toolbars, search/filter text inputs must use a full-width row and must not be clipped; the icon-only action row sits below/after the text input.
  • When a responsive/mobile toolbar has at least two actions, FlatPage adds a compact action-grid toggle to collapse or expand the complete action row. Search/filter text remains full width and visible, while the action row defaults collapsed to preserve content space. Configure it with MobileToolbarActionsCollapsible; set MobileToolbarActionsExpandedByDefault="true" only when a page intentionally starts expanded. Desktop actions always remain visible.
  • In desktop inline filter forms, action buttons align their visible top and bottom edges with adjacent dense outlined controls. On responsive layouts, move the action to its own full-width row instead of preserving desktop alignment offsets.
  • Grid toolbar actions are icon-only and kept on one horizontal line. Use accessible aria-label/title text for Import, Export, Download CSV, Print, and Refresh, but do not show those labels as button text in the toolbar.
  • Mobile pull-to-refresh is page-level opt-in and becomes active only when PullToRefreshEnabled=true and a real OnRefresh handler are both supplied. Enable it explicitly for mobile data/list/grid, monitoring, report, or feed pages where the gesture unambiguously reloads the latest data; never infer it from FlatPageKind or enable it globally.
  • Keep pull-to-refresh off by default for login/authentication, settings and account editing, create/edit forms, detail pages with unsaved state, dialogs/bottom sheets, and public landing/content pages unless that page deliberately defines the gesture. It starts only at the top of the document and the page-owned primary mobile scroll region on touch/coarse input. Incidental nested scrollers and editor/overlay/input/button/FAB targets remain excluded. The native-friendly handler uses non-passive touchmove so Android/iOS WebView scrolling cannot consume an active downward pull, while refresh still reuses the same single-flight pipeline and preserves query state.
  • Responsive Web/Hybrid behavior uses desktop tables/header filters above 900px; dedicated cards retain the identical query state at 900px and below; two card columns are used from 601px through 900px and one at 600px and below. The transition is reversible during live window resize without reload, desktop overflow returns to the grid-owned scroll region, and operational grids never create page-level horizontal scrolling.
  • Sidebar menu glyphs stay compact at 18px for root/parent items and 17px for nested items. Keep the existing icon column, text offset, dotted connector, and recursive parent/child alignment unchanged; reducing the glyph must not shift menu geometry.
  • Nested sidebar typography and geometry are depth-driven, never expansion-state-driven. A child group such as ERP - Human Resources keeps the same 11px text, 17px icon, 32px row, and text coordinate before and after its first expand/collapse interaction.
  • Browser preview validates responsive Web layout only. MAUI claims additionally require emulator/device checks for keyboard/IME resize, safe areas/notch, status bar, system back/swipe, orientation, lifecycle, permissions, native gestures, and offline/reconnect behavior.
  • Android MAUI hosts use host-owned transparent edge-to-edge status-bar integration: obtain the real top WindowInsets, render the AppBar at 60px + inset, keep its controls in the lower 60px, and refresh status-icon contrast on Light/Dark/Auto, system-theme, and palette changes. Do not hardcode status-bar height or apply this native geometry to Web/Windows.
  • Mobile grid filters use MobileGridFilterSheet: dimmed overlay, top drag handle, compact Filter data header, full-width fields, and a fixed footer with Reset / Apply.
  • Grid filtering supports desktop column filters and mobile bottom-sheet filters; disabled columns stay out of mobile filters.
  • Save/submit actions should pass Saving=true to disable form actions and prevent accidental close while processing.
  • Release builds remove PDB output by default.

Core components

  • FlatMudProviders
  • FlatAppShell
  • FlatAppBar
  • FlatSidebar
  • FlatPage
  • FlatPageHeading
  • FlatPanel
  • FlatStatCard
  • FlatEmptyState
  • FlatInfoItem
  • FlatDetailSection
  • FlatDataGrid<TItem>
  • FlatGroupedDataGrid<TItem>: expandable stable-key groups, localization-aware host-supplied summaries, typed toggle/row callbacks, and equivalent responsive cards; see Grouped Data Grid.
  • FlatHierarchyDesigner: compact ordered outline editing with Web drag/drop, accessible move actions, cycle prevention, exact parent/order results, and versioned nested JSON export; see Compact Hierarchy Designer.
  • FlatEditableGrid<TItem>: one-draft inline Add/Edit/Delete grid with typed canonical save results and per-row Create/Update/Delete outcome callbacks; switches to equivalent card editing at 900px and below.
  • FlatModelCrud<TItem> and FlatModelForm<TItem>: metadata-driven list/card CRUD and form generation from DataAnnotations, with outlined floating labels by default, Display(Prompt) hints, localized numeric DisplayFormat, built-in local/async searchable combos, per-field visual EditorTemplate, explicit image templates, reusable visual layouts, and host-owned persistence.
  • FlatModelFormDesigner<TItem>: drag/drop or keyboard-accessible field ordering, visible/span controls, bounded margin/padding, validated CSS class tokens, and exact desktop/mobile FlatModelForm live preview for native, searchable-combo, image, and custom visual editors.
  • ERP application building blocks: FlatTransactionWorkspace<THeader,TLine>, FlatEntityLookup<TItem> with a sortable/searchable table grid, FlatMoneyInput, FlatQuantityInput, FlatJournalEntryGrid<TLine>, FlatReconciliationWorkspace<TLeft,TRight>, FlatPlanningBoard<TItem,TResource>, FlatRecordLifecycleHeader, and FlatBackgroundOperationCenter. Lookup headers toggle ASC/DESC, search targets the active sorted column, search autofocuses on open, and letter/number typing elsewhere inside the modal routes directly into search. These components own responsive presentation and typed intent only; business rules and persistence remain host-owned. See ERP toolkit.
  • FlatImageUpload: multiple image selection with responsive preview, configurable high-resolution autoscale, exact original/output metadata, progress/cancel/retry, and host-owned API/storage callbacks.
  • FlatDynamicMenu: autoload and validate recursive sidebar navigation from MenuText, Id, ParentId, Url, and Icon, with conversion for horizontal and bottom navigation. IFlatNavigationRouteResolver applies consumer-owned label mappings consistently in Web/MAUI, normalizes hidden Unicode, and rejects unsafe fallback schemes.
  • FlatMobileGrid<TItem>
  • FlatPager
  • FlatFab
  • FlatProfileAvatar
  • FlatProfileListItem for compact responsive people/member directories with a circular avatar, identity metadata, host-defined badges, and a navigation callback
  • FlatDisplaySettings
  • FlatHorizontalNavigation
  • FlatBottomNavigation: phone navigation bar backed by the shared route tree, with active-route state, overflow, and recursive child-menu sheets.
  • FlatKanbanBoard<TItem>
  • FlatKanbanCard
  • FlatPipelineCard and FlatKanbanBoardVariant.Pipeline for aggregate stage/deal layouts
  • FlatChatShell
  • FlatChatConversationItem
  • FlatChatMessage
  • FlatChatTypingIndicator
  • FlatChatWebSocketClient
  • AI Chat template composition: provider-neutral assistant history, prompts, responding/stop states, and mobile history/thread navigation built from the shared Chat components.
  • FlatWidget
  • FlatMetricWidget
  • FlatActionMetricWidget
  • FlatCompactMetric
  • FlatProgressWidget
  • FlatSegmentProgressWidget
  • FlatActivityItem
  • FlatTaskItem
  • FlatEmailShell
  • FlatEmailFolderItem
  • FlatEmailMessageItem
  • FlatCatalogGrid<TItem>
  • FlatCatalogCard
  • FlatFilterWorkspace: desktop filter rail plus result toolbar/content; switches to a staged mobile BottomSheet with Apply/Reset/Dismiss callbacks.
  • FlatProductDetail and FlatProductMetric: responsive gallery/summary detail shell with host-owned metadata, metrics, variants, tabs, and actions.
  • FlatEditorWorkspace and FlatEditorSection: responsive main-editor/settings-rail composition for create/edit pages.
  • MobileGridFilterSheet
  • BottomSheet
  • CrudEditorShell
  • FlatFormModal
  • FlatProcessingContainer: reusable single-flight processing boundary for pages, panels, and forms with disabled content, optional backdrop/cancel action, and lifecycle callbacks. Cancel operation is hidden by default; opt in with CanCancel="true" plus CancelActionVisible="true" (or AllowProcessingCancellation plus ProcessingCancelVisible on form modals).
  • FlatDataGridSkeleton: responsive MudSkeleton-based initial-load placeholder with desktop table rows and equivalent mobile/tablet cards. Keep established data visible on later refresh/filter/sort/paging operations.
  • FlatPageSkeleton: automatic responsive initial-load templates selected by FlatPageKind, with global FlatLoadingOptions and per-page template/count/custom-content overrides.
  • FlatCardGrid<TItem>
  • FlatProfileCard
  • FlatTimeline<TItem>: center and left timeline shell with marker/date selectors and host-owned item templates.
  • FlatMultiSelect<T>
    • responsive dense multi-value selector with standardized compact field geometry, one native selection indicator, optional icon/avatar content, and hideable checkbox column; see Multi-select component
  • FlatSearchComboBox<T>: searchable single-value selector with typed binding, local text/description/keyword matching, and optional cancellable async search.
  • FlatMaterialIconPicker: searchable Material icon selector backed by the installed MudBlazor Filled and Outlined catalogs. It pages large result sets, supports keyboard/touch selection, and returns a typed FlatMaterialIconSelection containing the stable icon name, SVG value, and style. See IconPicker usage for Indonesian button/empty-state labels and host-owned persistence.
  • FlatReconnectModal: library-owned Blazor Server reconnect notice with theme-aware responsive states and appsettings-backed text.
  • FlatSessionRestore: full-page session-bootstrap status using the exact shared reconnect spinner; host session lookup, validation, authentication state, and failure handling remain host-owned.
  • FlatDeviceNotification: borderless notification action that invokes a host-owned local OS/device notification service and reports shown, denied, unsupported, or failed state without falling back to a snackbar.

Core services

  • FlatSessionCartService<TItem>: scoped per user/session cart-like state for ecommerce carts, selection baskets, wishlist-like flows, and other per-session item collections.
  • FlatUiPreferencesService: scoped display-preference state with Vertical, Web-only Horizontal, and Web/MAUI Bottom navigation resolution, host-configured color palettes, Compact/Default/Comfortable density presets, and a configurable font size. Set OpxFlatUi:Display:HostKind to Web or MauiHybrid. Host defaults and palette definitions are read from appsettings; user overrides store only the selected palette ID and display choices per browser through localStorage.
  • FlatPageLoadingState: reference-counted shared loading state for the AppBar loading line. Register it as scoped in Blazor Web or singleton in a MAUI Blazor Hybrid host, inject it into page/service operations, and wrap work with using var loading = PageLoading.Begin();. Real route/query navigation also shows the same compact 2px indeterminate line automatically; same-URL modal history guards are ignored so modal open/close does not flash loading.
  • IDeviceNotificationService: host boundary for local device notifications. Blazor Web can use FlatWebDeviceNotificationService; MAUI registers a native platform adapter.

Implementation guides

  • Loading table/grid data from an API: recommended typed-client and Razor pattern for server paging, sorting, filtering, cancellation, stale-response protection, AppBar loading, error/empty states, authentication boundaries, and desktop/mobile parity.
  • Grouped Data Grid: expandable grouped rows, host-owned summary values, responsive cards, typed callbacks, and usage.
  • Editable grid: reusable Add, inline Edit, Save, Cancel, Delete, validation, host-owned persistence callbacks, and responsive card editing.
  • Model-driven CRUD: automatic list grid, responsive cards, and create/edit form generation from model metadata.
  • Visual model form designer: reusable form layout metadata, live preview, spacing/class validation, and host-owned persistence.
  • Dynamic menu: recursive autoload navigation, validation, search, active ancestry, and host-owned API/authorization boundaries.
  • ERP sample pages: route matrix, responsive behavior, extension workflow, and static-versus-live integration boundaries.
  • Authentication and navigation templates: two-step verification workflow and optional horizontal desktop navigation.
  • Email template: reusable mailbox folders, message list, reading pane, compose workflow, responsive behavior, and mail-service boundaries.
  • Kanban template: generic board contract, card movement, WIP limits, filtering, responsive behavior, and persistence boundary.
  • Filter workspace: desktop filter rail, mobile filter sheet, status/search toolbar, grid/card parity, and host-owned query state.
  • Product detail: responsive gallery, metrics, variants, specification tabs, edit boundary, and host-owned data contract.
  • Editor workspace: main form/settings rail, responsive stacking, upload/tags composition, and host-owned save contract.
  • Calendar: reusable Year/Month/Week/Day/List calendar, responsive year month-grid, mobile agenda, typed callbacks, and host-owned scheduling boundary.
  • Vector map: provider-neutral SVG floor plans, projected locations, tracking trails, routes, markers, viewport state, and host-owned GPS/routing boundaries.
  • Asset layout: positioned machines, computers, servers, and devices with optional type/zone metadata, searchable selection, responsive detail, and typed host-owned move/rotation intents.
  • Chat template: conversation list, responsive thread shell, message/composer components, accessibility, and live integration boundaries.
  • AI chat template: provider-neutral assistant workspace, local simulation, responsive history/thread flow, cancellation, and secure host integration boundaries.
  • Widgets: Velzon-inspired metric, progress, activity, and content widget components.
  • Form modal: simple @bind-Open form dialog with size, saving, validation, close, and custom-footer parameters.
  • Card grid: searchable Grid/List container with reusable profile/member cards and responsive behavior.
  • Reconnect notice: default Blazor Server override, appsettings text, host placement, framework state contract, and safe visual preview.
  • Device notifications: reusable action, Web Notification API adapter, MAUI native adapter boundary, permissions, and security guidance.

Sample application

This repository includes a Blazor Web sample app:

dotnet run --project samples\Opx.MudBlazor.FlatUi.Sample\Opx.MudBlazor.FlatUi.Sample.csproj

Sample pages:

  • /file-upload demonstrates host-owned multiple upload, validation, progress, cancel, retry, and removal.

  • /grid-preferences demonstrates visibility, order, width, pinning, saved-view callbacks, reset, and virtualization contracts.

  • /tree-grid demonstrates reusable hierarchy rows, expand/collapse, drag/drop, cycle prevention, and host-persisted parent keys.

  • /hierarchy-designer demonstrates a compact report-style outline, drag/drop and accessible movement, edit intent, and versioned JSON export.

  • /tree-grid demonstrates reusable hierarchy rows, expand/collapse, drag/drop, cycle prevention, and host-persisted parent keys.

  • /file-upload demonstrates host-owned multiple upload, validation, progress, cancel, retry, and removal.

  • /grid-preferences demonstrates visibility, order, width, pinning, saved-view callbacks, reset, and virtualization contracts.

  • Dashboard: KPI cards, multipurpose chart, timeline, and priority table. Its default composition has no visible Refresh action; eligible mobile refresh is provided through the explicit pull-to-refresh handler and synchronized AppBar loading line.

  • Jobs dashboard: hiring KPIs, trend chart, activity feed, filtered role board, and sample create-job modal.

  • Login: standalone full-screen auth page with compact text/combo style and sample-only sign-in flow.

  • CRUD: desktop grid, mobile cards, filter bottom sheet, paging, and an editor shell demonstrating CloseOnOutsideClick="true".

  • CRUD Simple: minimal list page with only Add action and a compact CRUD editor form demonstrating the default explicit Back/Cancel-only dismissal.

  • Email: responsive mailbox folders, searchable message list, reading pane, attachment card, reply/forward/delete, compose editor, mobile FAB, and sample-only pull-to-refresh.

  • Edit Account: responsive user-account form with photo/initial avatar fallback, profile details, locale preferences, security summary, optional password change, and in-memory Save/Cancel behavior.

  • Monitoring: service health table, incident feed, and device cards.

  • Monitoring Database: mobile-first read-only database status list with search, source marker, filter, status chips, and compact fact cards.

  • Static / Master: read-only master-data style page.

  • Reports: reusable operational report viewer with filter parameters, KPI summary, grouped desktop table, subtotal/grand total, drill-down, export callbacks, and grouped mobile cards; see reporting documentation.

  • Calendar: reusable Year/Month/Week/Day/List scheduling surface with a responsive 12-month grid, optional category/upcoming-events rail, host-owned event callbacks, and a compact mobile agenda.

  • Vector Map: interactive SVG floor-plan regions, projected GPS marker snapshots, tracking trails, preferred/alternative routes, zoom/reset controls, and exact host-owned selection callbacks.

  • Spatial Operations: reusable list-to-map workspace with mutually exclusive floors, overlay layers, polygon/circle geofences, route playback intents, exact item selection, and responsive desktop/mobile composition.

  • Asset Layout: reusable machine/computer/device map over typed vector regions with optional type/zone selectors, controlled selection/edit state, and host-validated movement requests.

  • Product Catalog: ecommerce-style product cards, desktop filter rail, result-toolbar search, staged category/price filter sheet at tablet/mobile widths, stock, rating, wishlist, and cart action.

  • Website Front: public landing/front page shell with hero, CTA buttons, featured catalog cards, feature blocks, and footer.

  • Blog: public content listing with article cards.

  • ERP Overview: cross-module KPI, workflow inbox, responsive business-exception cards with collision-safe status columns, and drill-down module launcher.

  • Human Resources: overview, employee directory, and attendance/leave sample pages.

  • Production: production plan, work orders, progress, and quality-control sample pages.

  • Finance: overview, general ledger, accounts payable, and accounts receivable sample pages.

  • Supply Chain: procurement dashboard and responsive inventory sample pages.

  • Sales & Distribution: sales overview, fulfillment pipeline, and sales-order sample page.

  • Components: palette, empty state, stat cards, detail section, and usage snippet.

  • Charts: all eleven MudBlazor 9.7.0 chart types with responsive rendering and expandable copy-ready Razor samples.

Theme

Use FlatUiTheme.CreateTheme() for the MudBlazor theme and FlatUiTheme.CreateCssVariables() for runtime CSS variables when a host app needs branding overrides.

Set OpxFlatUi:Display:DefaultThemeMode to Auto, Light, or Dark. The default is Auto. Include _content/Opx.MudBlazor.FlatUi/opx-flat-ui-theme-bootstrap.js before stylesheets so a dark device starts on the dark background without a Light-theme flash. Theme mode is stored with the scoped display preferences; Cancel restores the prior mode and Restore clears the override.

Configuration and environment

  • OpxFlatUi:Display:DefaultDensity: Compact, Default, or Comfortable application default.
  • OpxFlatUi:Display:DefaultInputStyle: Standard, Filled, or Outlined; default and invalid-value fallback are Outlined. Settings live-previews and persists this scoped per-user choice. Reusable controls map it to the native MudBlazor Variant through FlatUiPreferencesService.InputVariant; an explicit component Variant remains an intentional override.
  • OpxFlatUi:Display:LightSidebarBackground, LightSidebarForeground, DarkSidebarBackground, and DarkSidebarForeground: six-digit hex app defaults for theme-specific navigation surfaces. Settings exposes accessible color and hex controls, live-preview, Save, Cancel, and Restore; invalid per-user values fall back independently to these normalized app defaults.
  • OpxFlatUi:Application: mandatory initial host metadata and branding used by the host document and Login template; configure it during scaffolding before feature-page development. Provide AppName, CompanyName, a Copyright template with {Year}/{CompanyName} tokens, plus LoginBrandBackgroundColor, optional LoginBrandBackgroundImageUrl, LoginBrandPanelVisible, LoginBrandOverlayColor, LoginBrandOverlayOpacity, and LoginLayout (Default or Boxed). Default with LoginBrandPanelVisible=true preserves the split desktop/current mobile composition; false hides the brand panel and centers the unboxed form. Boxed centers the same theme-safe form over the configured brand background. Render <meta name="author" content="@ApplicationOptions.ResolvedAuthor" /> once in the host document <head> so it applies to every route. Logo and LogoUrl are optional; leave both blank/null to render no logo or reserved gap. A configured Logo accepts a supported icon alias or trusted MudBlazor SVG path, while LogoUrl accepts a validated relative/HTTP(S) image. Colors require six-digit hex and opacity is clamped to 0-0.85; invalid values use safe defaults.
  • Login omits the duplicate top mobile identity row and any static security/sample footer banner. The local sample accepts operator@opx.local / sample; required or invalid credentials use the shared Error MessageBox with generic wording. Replace that local comparison in production hosts.
  • Unknown routes resolve the AppBar PageTitle to Not found; the Not Found sample uses the standard responsive page gutters instead of edge-aligned copy.
  • OpxFlatUi:Display:DefaultThemeMode: Auto, Light, or Dark; Auto resolves the device preference before first paint when the documented bootstrap is installed. Explicit Light/Dark overrides the device for the complete root and component tree; the bootstrap isolates opx-root-theme-* classes from shell theme-* classes to prevent mixed backgrounds and surfaces.
  • OpxFlatUi:Display:DefaultColorPalette: palette ID selected when no user override exists. Built-in IDs are blue, teal, violet, orange, trust, slate, ocean, emerald, rose, and fluent-blue.
  • OpxFlatUi:Display:ColorPalettes: optional replacement palette list. Each item defines Id, Label, Description, four Light accent tokens (Accent, AccentHover, AccentSubtle, AccentDark), four Dark/Night tokens (DarkAccent, DarkAccentHover, DarkAccentSubtle, DarkAccentDark), and optional semantic tokens (Secondary, Success, Warning, Danger). Colors must use six-digit hexadecimal notation.
  • OpxFlatUi:Display:UseAppFontSize: initial user preference for font ownership. false selects Device by default so the component tree follows the device/browser root (1rem) and accessibility scaling; true initially selects Manual. Users can switch Device/Manual in Settings and save that choice per user.
  • OpxFlatUi:Display:DefaultFontSizePx: initial Manual font size; the cross-platform OPX baseline is 16px. The saved Manual value is retained while Device mode is active, so switching back restores the user's last size.
  • OpxFlatUi:Display:DefaultFabShape: global mobile FAB shape, Circle (default) or Square. Invalid values fall back to Circle; an individual FlatFab may deliberately override it through Shape.
  • OpxFlatUi:Display:DefaultRoundedSizePx: shared button and bottom-sheet corner radius, clamped to 0-12. The default 0 preserves the flat design; cards, inputs, dialogs, menus, and other surfaces are intentionally unaffected. Users can preview and persist this value from Settings.
  • The 16px app baseline resolves information-dense screens to roughly 14px operational copy, 13px supporting copy, and 11px metadata. Interface density remains independent: Compact, Default, and Comfortable change spacing/control geometry without changing the selected font size.
  • OpxFlatUi:Display:MinimumFontSizePx and MaximumFontSizePx: limits exposed by FlatDisplaySettings when app-controlled font sizing is enabled.
  • OpxFlatUi:Display:StorageKey: browser storage key; use a unique value per host application.
  • OpxFlatUi:Grid:DefaultPageSize: global initial page size for GridViewState; normalized to 1-500. Construct page state with new GridViewState(gridOptions) so the initial API request also uses the configured value.
  • OpxFlatUi:Grid:PageSizes: global page-size choices for FlatPager. Values outside 1-500 are removed, duplicates are removed, and the normalized default is always included. A page may override these choices with the PageSizes parameter and may override its current size through SetPageSize(...).
  • OpxFlatUi:Grid:DefaultHeaderStyle: global header presentation for FlatDataGrid, FlatGroupedDataGrid, and FlatEditableGrid; package default/fallback is CompactSearch.
  • OpxFlatUi:Grid:ShowHeaderIcons: globally shows optional GridColumnDefinition.HeaderIcon metadata in compact headers; package default is false. Search, sort, and filter affordances remain available.
  • OpxFlatUi:Reconnect: reconnecting, paused, failed, and retry text used by FlatReconnectModal; restart the host after changing these startup-bound values.
  • A server restart discards the old Blazor Server circuit. The reconnect notice reaches the rejected state and Try again performs the required full reload to create a fresh circuit. The sample enables detailed circuit diagnostics only in Development; keep them disabled in Production.
  • OpxFlatUi:Snackbar:HideTransitionDurationMs: global snackbar fade-out duration. The OPX baseline is 200 ms, normalized to 100-3000 ms; bind FlatSnackbarOptions before AddMudServices and assign SnackbarConfiguration.HideTransitionDuration. This does not shorten the visible message duration.
  • OpxFlatUi:DeviceNotification: optional showroom/default notification title, message, icon URL, and tag; real application payloads normally come from the active use case.
  • The sample provides safe baseline, Development, Staging, and Production configuration files. Environment-specific files inherit the baseline display defaults unless overridden.
  • There are no project-specific environment variables. Standard ASPNETCORE_ENVIRONMENT selects Development, Staging, or Production; set it explicitly in deployment and restart the host after changing it.

Example custom host palette:

{
  "OpxFlatUi": {
    "Display": {
      "AppBarSearchVisible": true,
      "DefaultColorPalette": "brand",
      "ColorPalettes": [
        {
          "Id": "brand",
          "Label": "Brand",
          "Description": "Host application accent.",
          "Accent": "#0067c0",
          "AccentHover": "#005a9e",
          "AccentSubtle": "#e5f1fb",
          "AccentDark": "#004578",
          "DarkAccent": "#4cc2ff",
          "DarkAccentHover": "#75d1ff",
          "DarkAccentSubtle": "#102c3b",
          "DarkAccentDark": "#a6e2ff"
        }
      ]
    }
  }
}

When ColorPalettes is supplied it replaces the built-in choice list. Invalid color values fall back to safe OPX defaults. Restart the host after changing appsettings; Restore application defaults clears the browser override and applies the configured default palette.

  • Accordion: reusable default/flush disclosure groups with optional icons, single/multiple expansion, disabled state, and responsive theme parity.
  • Job Landing: public career portal composition with search hero, hiring process, category discovery, responsive role results, featured employers, typed email-application callback, and host-owned delivery/storage.
  • Page identity and prompt routing defines stable unique PageIds for every sample route and maps future page prompts to the correct source archetype.
  • Spatial operations documents layer/floor selection, geofences, synchronized work items, route playback, responsive behavior, and host-owned integration boundaries.

Hybrid reliability hardening

See P0–P2 hybrid hardening for native scroll arbitration, overlay Back, keyboard refresh, resume retention, explicit retry and artifact evidence.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.1.45 71 9/30/2026
2.1.44 82 9/27/2026
2.1.43 87 9/24/2026
2.1.42 90 9/23/2026
2.1.41 96 9/23/2026
2.1.40 99 9/21/2026
2.1.38 94 9/20/2026
2.1.37 97 9/18/2026
2.1.36 105 9/17/2026
2.1.35 94 9/17/2026
2.1.34 115 9/15/2026
2.1.33 99 9/15/2026
2.1.32 100 9/14/2026
2.1.31 93 9/14/2026
2.1.30 99 9/13/2026
2.1.29 104 9/12/2026
2.1.27 99 9/11/2026
2.1.26 101 9/10/2026
2.1.25 106 9/10/2026
2.1.24 99 9/10/2026
Loading failed