Concept

Variants

Register your own render template for any component — slot it in alongside the built-ins with a strongly typed variant id.

What a variant is

A variant is a RenderFragment keyed on a typed id. Built-in variants (e.g. BOBButtonVariant.Default, BOBThemeSelectorVariant.SunMoon) are hard-coded inside the component; custom variants are registered at startup and resolved by the IVariantRegistry singleton at render time.

Components that support variants derive from BOBVariantComponentBase<TComponent, TVariant>. Inside they expose a dictionary of built-in templates and delegate unknown ids to the registry.

Define a variant type

Every variant type inherits Variant and exposes static named instances.

MyButtonVariant.cs
public sealed class MyButtonVariant : Variant
{
    public static readonly MyButtonVariant Gradient = new("Gradient");
    public static readonly MyButtonVariant Ghost    = new("Ghost");

    public MyButtonVariant(string name) : base(name) { }
}

Register a template

Register in Program.cs via AddBlazOrbitVariants. The builder's ForComponent<T>() scopes registrations to a concrete component type.

Program.cs
builder.Services.AddBlazOrbit();

builder.Services.AddBlazOrbitVariants(b =>
{
    b.ForComponent<BOBButton>()
     .AddVariant(MyButtonVariant.Gradient, button => @<bob-component @attributes="button.ComputedAttributes">
         <button class="my-gradient-btn" @onclick="button.HandleClick">
             @button.Text
         </button>
     </bob-component>)
     .AddVariant(MyButtonVariant.Ghost, button => @<bob-component @attributes="button.ComputedAttributes">
         <button class="my-ghost-btn" @onclick="button.HandleClick">@button.Text</button>
     </bob-component>);
});

Use the variant

MyPage.razor
<BOBButton Text="Subscribe"
           Variant="MyButtonVariant.Gradient"
           OnClick="HandleSubscribe" />

<BOBButton Text="Skip"
           Variant="MyButtonVariant.Ghost"
           OnClick="HandleSkip" />

Pass your custom variant through the component's Variant parameter. The framework calls your registered RenderFragment with the live component instance, so you can bind to its parameters, state, and callbacks.

Tips

  • Variants always run through BOBComponentAttributesBuilder first — the root <bob-component> gets the usual data-bob-* treatment whether you override the template or not.
  • Variants are singletons. Don't close over mutable state; use component parameters instead.
  • For one-off layouts you'd rather inline, use the component's slots (e.g. ChildContent, Header) instead of a registered variant.
  • Create a custom variant via SomeVariant.Custom("name") when the type exposes it, or subclass Variant directly.