Almost every component should support parameter passing. Rather than coding it into every component, you should create a base class to support it. In the base class shown the CaptureUnmatchedValues function is used. This function finds all parameters that do not match to a defined parameter and stores the attribute name and value in the associated dictionary.

To render all of the attributes in the dictionary to an html element you use the @attributes function passing it a Dictionary parameter with the attribute names and values.

<div @attributes=@RenderAttributes()>

Having the attributes in a Dictionary makes it easier to modify attributes. HTML attributes always have a lowercase name. To avoid name conflicts parameters should always start with a capital letter and the HTML attributes should always be passed as unmatched values with the actual HTML lower case attribute name like class and style.

JmhComponentBase class contains a Dictionary of JmhComponentPart classes. Each part instance contains a Dictionary for attributes.

In the JmhComponentBase we use Render methods to render the attributes for a part. In this example we pass the red-black class name to the Dialog part by using a part name indexer. The dialog element does not inherit background-color or color so placing the class on the root element will not work. We must add it to the class attribute in the Dialog part attributes dictionary.

<Modal class=”[Dialog]red-black”>

@inherits JmhComponentBase;
<div @attributes="@Render()">
    <dialog @attribute="@Render(Dialog)”>
       <div @attribute="@Render(Content)">

When we render, we render from the dictionaries in the part classes. These dictionaries will automatedly add the component name to the root class attribute and Lpart class names to the part class attribute.

It will render as:

<div class=”Modal” >
<dialog class=”Modal-Dialog red-black” >
<div class=”Modal-Content” >

If we were to create a Dialog component and use it instead of the html dialog element:

<Modal class=”[Dialog]red-black”>

@inherits JmhComponentBase;
<div @attributes="@Render()">
    <Dialog @attribute="@Render(Dialog)”>

It would render as:

<div class=”Modal” >
<dialog class=”Dialog Modal-Dialog red-black” >
<div class=”Dialog-Content” >

@inherits ComponentBase
@inject ILogger<JmhComponentBase> logger;

@code {
    [Parameter(CaptureUnmatchedValues = true)]
    public IDictionary<string, object>? ComponentAttributes { get; set; }

    internal bool hasRendered = false;

    public string? TagName { get; private set; } = null;

    public Dictionary<string, JmhComponentPart> ComponentParts { get; private set; } = new();
    private const string RootPartName = "RootPart";
    public JmhComponentPart? RootPart = null;

    protected override void OnInitialized()
    {
        base.OnInitialized();
        // add name of component to CssClassNames
        TagName = this.GetType().Name;
        RootPart=CreateComponentPart(RootPartName);

    }

    /// <summary>
    ///  
    /// </summary>
    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        if (ComponentAttributes is not null)
        {
            ParseComponentAttributes();
        }

    }


    protected override void OnAfterRender(bool firstRender)
    {
        base.OnAfterRender(firstRender);
        if (firstRender)
        {
            hasRendered = true;
            FirstRender();
        }
    }

    /// <summary>
    /// Helper for FirstRender. 
    /// </summary>
    protected virtual void FirstRender()
    {

    }

    /// <summary>
    /// StateHasChanged is private so only the component can call it.
    /// We make it available to other internal classes.
    /// A call to StateHasChanged before FirstRender will throw an exception.
    /// </summary>
    internal void ChangeEvent()
    {
        if (hasRendered)
        {
            StateHasChanged();
        }
    }   

    /// <summary>
    /// We create the CPart in the base class. 
    /// The other parts are added in the extended classes.
    /// </summary>
    /// <param name="partName">
    /// <returns></returns>
    public JmhComponentPart CreateComponentPart(string partName)
    {
        if (string.IsNullOrEmpty(partName))
        {
            throw new Exception("Root Part Name can not be NullorEmpty");
        }
        JmhComponentPart part = new(partName);
        string? requiredClass = TagName;
        if (!partName.Equals(RootPartName))
        {
            requiredClass = TagName + "-" + part.PartName;
        }

        part.CssClassNames.AddRequiredClass(requiredClass!);
        ComponentParts.Add(partName, part);

        return part;
    }
}