SCABlazor 1.0.0

dotnet add package SCABlazor --version 1.0.0
                    
NuGet\Install-Package SCABlazor -Version 1.0.0
                    
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="SCABlazor" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SCABlazor" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="SCABlazor" />
                    
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 SCABlazor --version 1.0.0
                    
#r "nuget: SCABlazor, 1.0.0"
                    
#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 SCABlazor@1.0.0
                    
#: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=SCABlazor&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=SCABlazor&version=1.0.0
                    
Install as a Cake Tool

SCABlazor

SCABlazor is an original Blazor UI component framework built as a Razor Class Library. It uses .NET 10, nullable reference types, code-behind component logic, CSS isolation, design-token themes, and small JavaScript ES modules for browser behaviors that need JS interop.

The library is intentionally developed in phases. Phase 7 evolves the lightweight Grid into a stronger v3 foundation with row selection, text filtering, column width and visibility controls, density modes, improved paging, row actions, and application-managed state persistence while keeping advanced enterprise grid features deferred to future work.

Implemented Components

Phase 1:

  • SCAButton
  • SCAIconButton
  • SCATextBox
  • SCACheckBox
  • SCAPopup

Phase 2:

  • SCASelect
  • SCAToastService, SCAToastProvider, SCAToastContainer
  • SCACard
  • SCATabs, SCATabPage
  • SCADropdown
  • SCAFormLayout, SCAFormLayoutItem

Phase 4, Phase 5, and Phase 7:

  • SCAGrid<TItem>
  • SCAGridColumn<TItem>
  • Single and multiple row selection
  • Optional checkbox selection column
  • Text filter row
  • Column width, min width, max width, and visibility
  • Compact, normal, and comfortable density modes
  • Page size selector and pager summary
  • Persistent grid state snapshot/apply foundation
  • Grid state and server-side data request/result APIs

Architecture Principles

  • Original implementation with stable, discoverable My* public APIs.
  • Razor markup stays focused on rendering; component logic lives in .razor.cs partial classes.
  • Component visuals use .razor.css isolation and shared CSS variables.
  • Static assets are served from _content/SCABlazor/.
  • Browser behavior uses component-focused JS modules, not global scripts.
  • Inputs integrate with EditForm through InputBase<TValue>.
  • Public services are registered through builder.Services.AddSCABlazor().

Solution Structure

src/
  SCABlazor/
    Components/
      Button/
      IconButton/
      TextBox/
      CheckBox/
      Popup/
      Select/
      Toast/
      Card/
      Tabs/
      Dropdown/
      FormLayout/
      Grid/
    Core/
      Data/
    Services/
    Interop/
    Themes/
    Utilities/
    Extensions/
    wwwroot/
      themes/
      js/
  SCABlazor.Docs/
  SCABlazor.Playground/
tests/
  SCABlazor.BUnitTests/

Core/Data contains a minimal internal data request/sort foundation for future data components. The public Grid v3 APIs live under Components/Grid.

Installation

Reference the Razor Class Library from a Blazor app:

dotnet add <YourApp>.csproj reference src/SCABlazor/SCABlazor.csproj

Register services in Program.cs:

using SCABlazor.Extensions;

builder.Services.AddSCABlazor();

AddSCABlazor() registers:

  • SCAJsModuleService
  • SCAToastService

Static Web Assets And Themes

Include one theme and the shared base stylesheet in your app document:

<link rel="stylesheet" href="_content/SCABlazor/themes/light.css" />
<link rel="stylesheet" href="_content/SCABlazor/scablazor.css" />

Use the dark theme by swapping the theme file:

<link rel="stylesheet" href="_content/SCABlazor/themes/dark.css" />

JavaScript modules are loaded by components through SCAJsModuleService:

  • _content/SCABlazor/js/popup.js
  • _content/SCABlazor/js/dropdown.js

Usage Examples

<SCAButton OnClick="SaveAsync">Save</SCAButton>

<SCAIconButton AriaLabel="Refresh">
    <Icon><span>R</span></Icon>
</SCAIconButton>

<SCATextBox @bind-Value="model.Name" Placeholder="Name" ShowClearButton="true" />

<SCACheckBox @bind-Value="model.IsActive" Label="Active" />
<SCAPopup @bind-Visible="isPopupVisible" Title="Confirm" ShowFooter="true">
    <ChildContent>
        <p>Continue with this action?</p>
    </ChildContent>
    <FooterTemplate>
        <SCAButton Variant="SCAButtonVariant.Secondary" OnClick="Cancel">Cancel</SCAButton>
        <SCAButton OnClick="Confirm">Confirm</SCAButton>
    </FooterTemplate>
</SCAPopup>
<SCASelect Items="countries"
          TextSelector="country => country.Name"
          ValueSelector="country => country.Code"
          @bind-Value="selectedCountryCode"
          Placeholder="Choose a country" />
<SCAToastProvider>
    @Body
</SCAToastProvider>

@code {
    [Inject] private SCAToastService Toasts { get; set; } = default!;

    private void Notify() => Toasts.ShowSuccess("Profile saved.", "Saved");
}
<SCACard Title="Account" Subtitle="Profile details">
    <p>Account content goes here.</p>
</SCACard>

<SCATabs @bind-ActiveIndex="activeTab">
    <SCATabPage Title="General">General content</SCATabPage>
    <SCATabPage Title="Security">Security content</SCATabPage>
</SCATabs>
<SCADropdown>
    <TriggerTemplate>
        <SCAButton>Open menu</SCAButton>
    </TriggerTemplate>
    <ChildContent>
        <button type="button">Profile</button>
        <button type="button">Settings</button>
    </ChildContent>
</SCADropdown>

<SCAFormLayout Columns="2">
    <SCAFormLayoutItem Label="First name">
        <SCATextBox @bind-Value="model.FirstName" />
    </SCAFormLayoutItem>
    <SCAFormLayoutItem Label="Last name">
        <SCATextBox @bind-Value="model.LastName" />
    </SCAFormLayoutItem>
</SCAFormLayout>
<SCAGrid TItem="UserDto" Items="users" PageSize="10">
    <Columns>
        <SCAGridColumn TItem="UserDto" Title="Name" Field="user => user.Name" />
        <SCAGridColumn TItem="UserDto" Title="Email" Field="user => user.Email" />
        <SCAGridColumn TItem="UserDto" Title="Role" Field="user => user.Role" />
    </Columns>
</SCAGrid>
<SCAGrid TItem="UserDto" Items="users">
    <Columns>
        <SCAGridColumn TItem="UserDto" Title="Name" Field="user => user.Name">
            <CellTemplate Context="user">
                <strong>@user.Name</strong>
            </CellTemplate>
        </SCAGridColumn>

        <SCAGridColumn TItem="UserDto" Title="Actions" Sortable="false" Filterable="false">
            <CellTemplate Context="user">
                <span @onclick:stopPropagation="true">
                    <SCAButton Size="SCAButtonSize.Small">Edit</SCAButton>
                </span>
            </CellTemplate>
        </SCAGridColumn>
    </Columns>
</SCAGrid>
<SCAGrid TItem="UserDto"
        Items="users"
        SelectionMode="SCAGridSelectionMode.Multiple"
        ShowSelectionColumn="true"
        @bind-SelectedItems="selectedUsers"
        KeySelector="user => user.Id">
    <Columns>
        <SCAGridColumn TItem="UserDto" Title="Name" Field="user => user.Name" />
        <SCAGridColumn TItem="UserDto" Title="Email" Field="user => user.Email" />
        <SCAGridColumn TItem="UserDto" Title="Role" Field="user => user.Role" />
    </Columns>
</SCAGrid>
<SCAGrid TItem="UserDto"
        Items="users"
        FilterMode="SCAGridFilterMode.FilterRow"
        FiltersChanged="HandleFiltersChanged">
    <Columns>
        <SCAGridColumn TItem="UserDto" Title="Name" Field="user => user.Name" />
        <SCAGridColumn TItem="UserDto" Title="Role" Field="user => user.Role" />
        <SCAGridColumn TItem="UserDto" Title="Actions" Sortable="false" Filterable="false">
            <CellTemplate Context="user">
                <span @onclick:stopPropagation="true">
                    <SCAButton Size="SCAButtonSize.Small" Variant="SCAButtonVariant.Secondary">Edit</SCAButton>
                    <SCAButton Size="SCAButtonSize.Small" Variant="SCAButtonVariant.Danger">Delete</SCAButton>
                </span>
            </CellTemplate>
        </SCAGridColumn>
    </Columns>
</SCAGrid>
<label>
    <input type="checkbox" @bind="showEmailColumn" />
    Show Email
</label>

<SCAGrid TItem="UserDto"
        Items="users"
        Density="SCAGridDensity.Compact"
        PageSize="10"
        PageSizeOptions="new[] { 10, 20, 50 }">
    <Columns>
        <SCAGridColumn TItem="UserDto" Title="Name" Field="user => user.Name" Width="220px" MinWidth="160px" />
        <SCAGridColumn TItem="UserDto" Title="Email" Field="user => user.Email" Visible="showEmailColumn" MinWidth="240px" />
        <SCAGridColumn TItem="UserDto" Title="Role" Field="user => user.Role" Width="140px" />
    </Columns>
</SCAGrid>
<SCAGrid @ref="grid"
        TItem="UserDto"
        Items="users"
        FilterMode="SCAGridFilterMode.FilterRow">
    <Columns>
        <SCAGridColumn TItem="UserDto" Title="Name" Field="user => user.Name" />
        <SCAGridColumn TItem="UserDto" Title="Email" Field="user => user.Email" />
    </Columns>
</SCAGrid>

@code {
    private SCAGrid<UserDto>? grid;
    private SCAGridPersistentState? capturedState;

    private void CaptureState() => capturedState = grid?.GetPersistentState();

    private async Task ApplyStateAsync()
    {
        if (grid is not null && capturedState is not null)
        {
            await grid.ApplyPersistentStateAsync(capturedState);
        }
    }
}
<SCAGrid TItem="UserDto"
        DataProvider="LoadUsersAsync"
        PageSize="20">
    <Columns>
        <SCAGridColumn TItem="UserDto" Title="Name" Field="user => user.Name" />
        <SCAGridColumn TItem="UserDto" Title="Email" Field="user => user.Email" />
    </Columns>
</SCAGrid>

@code {
    private Task<SCAGridDataResult<UserDto>> LoadUsersAsync(SCAGridDataRequest request)
    {
        var query = users.AsEnumerable();

        foreach (var filter in request.Filters)
        {
            if (filter.FieldName == nameof(UserDto.Name) && !string.IsNullOrWhiteSpace(filter.Value))
            {
                query = query.Where(user => user.Name.Contains(filter.Value, StringComparison.OrdinalIgnoreCase));
            }
        }

        if (request.SortField == nameof(UserDto.Name))
        {
            query = request.SortDirection == SCAGridSortDirection.Descending
                ? query.OrderByDescending(user => user.Name)
                : query.OrderBy(user => user.Name);
        }

        var totalCount = query.Count();

        return Task.FromResult(new SCAGridDataResult<UserDto>
        {
            Items = query.Skip(request.PageIndex * request.PageSize).Take(request.PageSize).ToArray(),
            TotalCount = totalCount
        });
    }
}

SCAGrid supports client-side filtering, sorting, paging, single selection, multiple selection, column visibility, column sizing, density classes, page size selection, and persistent state snapshots when Items is used. When DataProvider is supplied, it takes precedence and receives SCAGridDataRequest values for page index, page size, sort field, sort direction, and active text filters.

Commands

Build the solution:

dotnet build

Run tests:

dotnet test

Run the docs app:

dotnet run --project src/SCABlazor.Docs

Run the playground app:

dotnet run --project src/SCABlazor.Playground

Pack the Razor Class Library:

dotnet pack src/SCABlazor/SCABlazor.csproj -c Release

Packaging Notes

The RCL project includes NuGet metadata, XML documentation generation, README packaging, and static web assets under wwwroot. The package is prepared for local packing, but it is not published by this repository.

Known Limitations

  • Grid v3 is intentionally lightweight.
  • Grid localStorage persistence, full column chooser UI, drag column resizing, column reordering, advanced filter menus, date/number filters, editing, grouping, virtualization, export, frozen columns, master-detail, and advanced keyboard navigation are not implemented yet.
  • Scheduler, Chart, Upload, RichTextEditor, and TreeView are not implemented.
  • SCASelect currently uses native <select> behavior rather than a custom virtualized listbox.
  • SCADropdown uses simple trigger-relative positioning.
  • Toast behavior is scoped to basic service-driven notifications.

Roadmap

Near-term hardening can continue with accessibility audits, visual regression coverage, package signing/publishing workflow, and richer examples. Future grid work can add localStorage state persistence, a column chooser component, drag resizing, column reordering, advanced filter operators per column, date and number filters, filter menus, editing, grouping, virtualization, export, frozen columns, and richer keyboard interaction without changing the basic Grid v3 API shape.

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
1.0.0 97 4/30/2026
0.1.0 90 4/30/2026

Initial SCABlazor package release based on the MyBlazorUI 0.3.1 codebase. Includes themed Blazor components, popup, toast, tabs, dropdown, form layout, and a lightweight grid with sorting, paging, selection, filtering, density modes, column visibility, column width support, page size selector, pager summary, and persistent grid state foundation.