DEV Community

Acmion
Acmion

Posted on

CshtmlComponent - Typed Slots

CshtmlComponent is a component framework, with an extensive feature set, for ASP.NET Core MVC and Razor Pages projects (not for Blazor). See the GitHub repository of CshtmlComponent here.

CshtmlComponent Named Slots

CshtmlComponent already supports the usage of named slots, but what about typed slots? This post will show how this can be achieved. This is not an extensive tutorial, so you should already be somewhat familiar with CshtmlComponent.

The Razor markup for a CshtmlComponent that supports named slots could look something like this:

@using SampleRazorPagesApplication
@model ExampleComponent

<div class="example-component">
    <h1>
        @Model.Title
    </h1>

    <div class="example-component-action-bar">
        @Html.Raw(Model.NamedSlots["ActionBar"])
    </div>

    <div class="example-component-child-content">
        @Html.Raw(Model.ChildContent)
    </div>
</div>

Initialization of a CshtmlComponent with Named Slots

The component could then be initialized with:

<ExampleComponent Title="Hello World">
    Some HTML that gets captured in Model.ChildContent.

    <CshtmlSlot Name="ActionBar">
        Some HTML that gets captured in Model.NamedSlots["ActionBar"].
    </CshtmlSlot>
</ExampleComponent>

Note that the slot name must be explicitly stated. This works, but is somewhat annoying and error prone. Luckily, fixing this is quite easy with typed slots.

Typed Slot Definition

To define a typed slot one should create a class that inherits CshtmlComponentSlot and set the Name property in the constructor:

[HtmlTargetElement("ExampleComponentActionBar"]
    public class ExampleComponentActionBar: CshtmlComponentSlot
    {
        public ExampleComponentActionBar(IHtmlHelper htmlHelper) : base(htmlHelper)
        {
            Name = "ActionBar";
        }
    }

That's it. You may wish to, for example, store the value for Name as a static field for better maintainability, but this is not necessary.

Initialization of a CshtmlComponent with Typed Slots

With the typed slot definition, the example component can now be initialized like this:

<ExampleComponent Title="Hello World">
    Some HTML that gets captured in Model.ChildContent.

    <ExampleComponentActionBar>
        Some HTML that gets captured in Model.NamedSlots["ActionBar"].
    </ExampleComponentActionBar>
</ExampleComponent>

Note that the name no longer has to be explicitly specified.

Conclusions

CshtmlComponent supports both named and typed slots. Typed slots bring many advantages, such as making maintenance and refactoring significantly easier. This feature is not yet documented in the actual CshtmlComponent documentation, but will be in the future.

Please try out CshtmlComponent! You just might find it useful for MVC and Razor Pages projects!

Top comments (0)