ComponentBuilder 3.1.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package ComponentBuilder --version 3.1.3                
NuGet\Install-Package ComponentBuilder -Version 3.1.3                
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="ComponentBuilder" Version="3.1.3" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add ComponentBuilder --version 3.1.3                
#r "nuget: ComponentBuilder, 3.1.3"                
#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.
// Install ComponentBuilder as a Cake Addin
#addin nuget:?package=ComponentBuilder&version=3.1.3

// Install ComponentBuilder as a Cake Tool
#tool nuget:?package=ComponentBuilder&version=3.1.3                

ComponentBuilder

Easy to create a Blazor Component Library with automation features supports both razor file way and RenderTreeBuilder way.

中文介绍 | Quick Start | Document

Latest Version .net6 .net7

✨ Features

  • Attribute first, easy define CSS from parameters
  • Easy to associate with components via Attributes
  • Cusomization CSS and attributes of component by coding logic
  • Both supports .razor file or RenderTreeBuilder to create component
  • Support Pre-definition for components with simular parameters
  • Dynamic JS interoption
  • New lifecycle definition of Component with interceptor design pattern
  • Renderer pipeline pattern to regonize dynamic render of components
  • More extensions for RenderTreeBuilder instance
  • Create element with Fluent API

🌈 Quick Start

  • In Button.razor file
@inherits BlazorComponentBase

<button @attributes="@GetAttributes()">
    @ChildContent
</button>

@code{
    [CssClass("btn")]
    public Button()
    {
    }

    [Parameter][CssClass("active")]public bool Active { get; set; } 
	
	[Parameter][CssClass("btn-")]public Color? Color { get; set; } 

	[Parameter]public RenderFragment? ChildContent { get; set; } 

	[Parameter][HtmlData("tooltip")]public string? Tooltip { get; set; }

	[Parameter][HtmlAttribute("onclick")]public EventCallback<ClickEventArgs> OnClick { get; set; } 

    [Parameter][HtmlAttribute]public string? Title { get; set; }
    
    public enum Color
    {
	    Primary,
	    Secondary,
	    [CssClass("info")]Information,
    }
}
  • In Button.cs component class for full automation features
[HtmlTag("button")]
[CssClass("btn")]
public class Button : BlazorComponentBase, IHasChildContent, IHasOnClick
{
	[Parameter][CssClass("active")]public bool Active { get; set; } 
	
	[Parameter][CssClass("btn-")]public Color? Color { get; set; } 

	[Parameter]public RenderFragment? ChildContent { get; set; }

	[Parameter][HtmlData("tooltip")]public string? Tooltip { get; set; }

	[Parameter][HtmlEvent("onclick")]public EventCallback<ClickEventArgs> OnClick { get; set; 

    [Parameter][HtmlAttribute]public string? Title { get; set; }
}

public enum Color
{
	Primary,
	Secondary,
	[CssClass("info")]Information,
}
  • Use component

<Button Color="Color.Primary">Submit</Button>

<button class="btn btn-primary">Submit</button>


<Button Active Tooltip="active button" Color="Color.Information" Title="click me">Active Button</Button>

<button class="btn btn-info active" data-tooltip="active button" title="click me">Active Button</button>

🔑 JS Interoption

  • Import modules
//in app.js
export function display(){
 // ...your code
}
[Inject]IJSRuntime JS { get; set; }

var js = await JS.Value.ImportAsync("./app.js");
js.display(); // same as function name
  • Evaluate js string
JS.Value.EvaluateAsync(window => {
    window.console.log("log")
});

JS.Value.EvaludateAsync(@"
    console.log(\"log\");
")
  • JS invoke C# code
JS.Value.InvokeVoidAsync("myFunction", CallbackFactory.Create<string>(arg=> {
    //get arg from js
}));

JS.Value.InvokeVoidAsync("calculate", CallbackFactory.Create<int,int>((arg1,arg2)=> {
    //get value of arg1,arg2 from js
}))
function myFunction(dotNetRef){
    dotNetRef.invokeMethodAsync("Invoke", "arg");
}

function calculate(dotNetRef){
    dotNetRef.invokeMethodAsync("Invoke", 1, 2);
}

ℹ️ Logical CSS/Style/Attributes

  • Logical CSS
protected override void BuildCssClass(ICssClassBuilder builder)
{
    if(builder.Contains("annotation-enter"))
    {
        builder.Remove("annotation-exist");
    }
    else
    {
        builder.Append("annotation-enter").Append("annotation-exist");
    }
}
  • Logical Attributes
protected override void BuildAttributes(IDictionary<string, object> attributes)
{
    attributes["onclick"] = HtmlHelper.Event.Create(this, ()=>{ ... });
    
    if(attrbutes.ContainKey("data-toggle"))
    {
        attributes["data-toggle"] = "collapse";
    }
}

🌴 Fluent API


builder.Div()
        .Class("my-class")
        .Class("active", IsActive)
        .Class("text-block", !string.IsNullOrEmpty(Name))
        .Style($"font-size:{Size}px", Size.HasValue)
        .Content("hello world")
       .Close();

builder.Component<Button>()
        .Class("my-class")
        .Class("active", IsActive)
        .Class("text-block", !string.IsNullOrEmpty(Name))
        .Style((Size.HasValue, $"font-size:{Size}px"))
        .Content(ChildContent)
       .Close();

builder.Ul().ForEach("li", result => {
    result.attribute.Content($"content{result.index}");
});

🚸 Component Association

In .razor file

  • For List.razor file be parent component
<ul @attributes="@GetAttributes()">
    <CascadingValue Value="this">
        @ChildContent
    </CascadingValue>
</ul>
  • For ListItem.razor file be child of List.razor component
<li @attributes="AdditionalAttributes">@ChildContent</li>

@code{
    [ChildComponent(typeof(List))]
    public ListItem()
    {
    }

    [CascadingParameter] public List CascadedList { get; set; }

    [Parameter] public RenderFragment? ChildContent { get; set; }
}

In RenderTreeBuilder

  • For List component class
[ParentComponent] //be cascading parameter for this component
[HtmlTag("ul")]
public class List : BlazorComponentBase, IHasChildContent
{

}
  • For ListItem component class
[ChildComponent(typeof(List))] //Strong association with List
[HtmlTag("li")]
public class ListItem : BlazorComponentBase, IHasChildContent
{
    [CascadingParameter]public List CascadedList { get; set; }

    [Parameter] public RenderFragment? ChildContent { get; set; }
}

Use in blazor

<List>
    <ListItem>...</ListItem>
</List>

<ListItem /> 

🔯 HtmlHelper

  • .razor
<div class="@GetCssClass"></div>

@code{
    string GetCssClass => HtmlHelper.Class.Append("btn-primary").Append("active", Actived).ToString();
}
builder.CreateElement(0, "span", attributes: 
    new { 
            @class = HtmlHelper.Class
                                .Append("btn-primary")
                                .Append("active", Actived),
            style = HtmlHelper.Style.Append($"width:{Width}px"),
            onclick = HtmlHelper.Event.Create<MouseEventArgs>(this, e=>{ //...click... });
        });

⚔️ Interceptors

You can intercept the lifecycle of component

  • Define an interceptor
public class LogInterceptor : ComponentInterceptorBase
{
    private readonly ILogger<LogInterceptor> _logger;
    public LogInterceptor(ILogger<LogInterceptor> logger)
    {
        _logger = logger;
    }

    //Run in SetParameterAsync method is called
    public override void InterceptSetParameters(IBlazorComponent component, ParameterView parameters)
    {
        foreach(var item in parameters)
        {
            _logger.LogDebug($"Key:{item.Name}, Value:{item.Value}");
        }
    }
}
  • Register interceptor
builder.Services.AddComponentBuilder(configure => {
    configure.Interceptors.Add(new LogInterceptor());
})

BlazorComponentBase Lifecycle

♻️ Renderer Pipeline

Recognize special case to render specified component

public class NavLinkComponentRender : IComponentRender
{
    public bool Render(IBlazorComponent component, RenderTreeBuilder builder)
    {
        if ( component is IHasNavLink navLink )
        {
            builder.OpenComponent<NavLink>(0);
            builder.AddAttribute(1, nameof(NavLink.Match), navLink.Match);
            builder.AddAttribute(2, nameof(NavLink.ActiveClass), navLink.ActiveCssClass);
            builder.AddAttribute(3, nameof(NavLink.ChildContent), navLink.ChildContent);
            builder.AddMultipleAttributes(4, component.GetAttributes());
            builder.CloseComponent();
            return false;
        }
        return true;
    }
}
  • Register renderer in configuration
builder.Services.AddComponentBuilder(configure => {
    configure.Renderers.Add(typeof(NavLinkComponentRenderer));
});

📘 Installation Guide

  • Install from Nuget.org
Install-Package ComponentBuilder
  • Register service
builder.Services.AddComponentBuilder();

Read document for more informations

📝 Component Library Solution Template

Use ComponentBuilder.Templates to generate a razor component library solution and online demo site

dotnet new install ComponentBuilder.Templates
dotnet new blazor-sln -n {YourRazorLibraryName}

More information see templates

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

NuGet packages (5)

Showing the top 5 NuGet packages that depend on ComponentBuilder:

Package Downloads
TDesign

基于腾讯 TDesign 的 Blazor 企业级组件库。腾讯 TDesign 官方地址:https://tdesign.tencent.com/

BlamanticUI

The css framework from Semantic-UI for blazor without jQuery.

ComponentBuilder.FluentRenderTree

用链式编程的方式简化 RenderTreeBuilder 的操作。 示例: builder.Element("div").Content("hello").Close(); builder.Component<Button>().Content("Button").Close(); builder.Div(Id is not null).Content(content => content.Component<Icon>().Attribute(m => m.Name, "user").Close()).Close();

ComponentBuilder.Interceptors.Diagnostics.Console

在控制台中用于组件生命周期诊断的拦截器,该拦截器可以用于调试阶段的生命周期运行的输出。

ComponentBuilder.Resolvers.FluentClass

组件参数支持 IFluentClassProvider 自动解析成 CSS 类。 [Parameter]public IFluentClassProvider Parameter{ get; set; } <Component Parameter="Provider.Is3.FromTop.HasSmall" />

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on ComponentBuilder:

Repository Stars
tdesign-blazor/TDesignBlazor
基于腾讯 TDesign 的 Blazor 组件库
Version Downloads Last updated
5.1.0 135 3/7/2024
5.0.0 190 12/21/2023
5.0.0-beta-1 157 11/16/2023
4.1.2 1,015 7/17/2023
4.1.1 204 7/17/2023
4.1.0 747 6/4/2023
4.0.0 483 5/30/2023
4.0.0-beta-3 259 5/22/2023
4.0.0-beta-2 140 5/19/2023
4.0.0-beta-1 145 5/17/2023
3.1.4 533 3/17/2023
3.1.3 200 3/16/2023
3.1.0 217 3/10/2023
3.0.0 741 2/24/2023
3.0.0-beta-0217 102 2/16/2023
3.0.0-beta-0206 185 2/6/2023
3.0.0-beta-0130 112 1/30/2023
3.0.0-beta-0114 119 1/13/2023
2.3.0 301 12/28/2022
2.2.0 297 12/13/2022
2.1.0 1,456 11/24/2022
2.0.0 367 10/28/2022
1.5.0.4 379 10/18/2022
1.5.0.3 397 10/13/2022
1.5.0.2 1,225 10/5/2022
1.5.0.1 399 10/3/2022
1.5.0 406 10/1/2022
1.4.1.1 672 9/19/2022
1.4.1 410 9/16/2022
1.4.0 424 9/15/2022
1.3.0 419 8/29/2022
1.2.1 581 7/12/2022
1.2.0 417 7/11/2022
1.1.0 561 5/22/2022
1.0.0 616 3/23/2022
0.7.0 444 3/11/2022
0.6.0 442 2/9/2022
0.5.0 276 1/6/2022
0.4.0 286 12/23/2021
0.3.0 299 12/16/2021
0.2.0 306 12/7/2021
0.1.0 6,152 11/24/2021