Skip to content

Latest commit

 

History

History
156 lines (100 loc) · 8.98 KB

th-components.md

File metadata and controls

156 lines (100 loc) · 8.98 KB
title author description monikerRange ms.author ms.date uid
Tag Helper Components in ASP.NET Core
rick-anderson
Learn what Tag Helper Components are and how to use them in ASP.NET Core.
>= aspnetcore-2.0
wpickett
06/12/2019
mvc/views/tag-helpers/th-components

Tag Helper Components in ASP.NET Core

By Scott Addie and Fiyaz Bin Hasan

A Tag Helper Component is a Tag Helper that allows you to conditionally modify or add HTML elements from server-side code. This feature is available in ASP.NET Core 2.0 or later.

ASP.NET Core includes two built-in Tag Helper Components: head and body. They're located in the xref:Microsoft.AspNetCore.Mvc.Razor.TagHelpers namespace and can be used in both MVC and Razor Pages. Tag Helper Components don't require registration with the app in _ViewImports.cshtml.

View or download sample code (how to download)

Use cases

Two common use cases of Tag Helper Components include:

  1. Injecting a <link> into the <head>.
  2. Injecting a <script> into the <body>.

The following sections describe these use cases.

Inject into HTML head element

Inside the HTML <head> element, CSS files are commonly imported with the HTML <link> element. The following code injects a <link> element into the <head> element using the head Tag Helper Component:

[!code-csharp]

In the preceding code:

  • AddressStyleTagHelperComponent implements xref:Microsoft.AspNetCore.Razor.TagHelpers.TagHelperComponent. The abstraction:
    • Allows initialization of the class with a xref:Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext.
    • Enables the use of Tag Helper Components to add or modify HTML elements.
  • The xref:Microsoft.AspNetCore.Razor.TagHelpers.TagHelperComponent.Order* property defines the order in which the Components are rendered. Order is necessary when there are multiple usages of Tag Helper Components in an app.
  • xref:Microsoft.AspNetCore.Razor.TagHelpers.TagHelperComponent.ProcessAsync* compares the execution context's xref:Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContext.TagName* property value to head. If the comparison evaluates to true, the content of the _style field is injected into the HTML <head> element.

Inject into HTML body element

The body Tag Helper Component can inject a <script> element into the <body> element. The following code demonstrates this technique:

[!code-csharp]

A separate HTML file is used to store the <script> element. The HTML file makes the code cleaner and more maintainable. The preceding code reads the contents of TagHelpers/Templates/AddressToolTipScript.html and appends it with the Tag Helper output. The AddressToolTipScript.html file includes the following markup:

[!code-html]

The preceding code binds a Bootstrap tooltip widget to any <address> element that includes a printable attribute. The effect is visible when a mouse pointer hovers over the element.

Register a Component

A Tag Helper Component must be added to the app's Tag Helper Components collection. There are three ways to add to the collection:

Registration via services container

If the Tag Helper Component class isn't managed with xref:Microsoft.AspNetCore.Mvc.Razor.TagHelpers.ITagHelperComponentManager, it must be registered with the dependency injection (DI) system. The following Startup.ConfigureServices code registers the AddressStyleTagHelperComponent and AddressScriptTagHelperComponent classes with a transient lifetime:

[!code-csharp]

Registration via Razor file

If the Tag Helper Component isn't registered with DI, it can be registered from a Razor Pages page or an MVC view. This technique is used for controlling the injected markup and the component execution order from a Razor file.

ITagHelperComponentManager is used to add Tag Helper Components or remove them from the app. The following code demonstrates this technique with AddressTagHelperComponent:

[!code-cshtml]

In the preceding code:

  • The @inject directive provides an instance of ITagHelperComponentManager. The instance is assigned to a variable named manager for access downstream in the Razor file.
  • An instance of AddressTagHelperComponent is added to the app's Tag Helper Components collection.

AddressTagHelperComponent is modified to accommodate a constructor that accepts the markup and order parameters:

[!code-csharp]

The provided markup parameter is used in ProcessAsync as follows:

[!code-csharp]

Registration via Page Model or controller

If the Tag Helper Component isn't registered with DI, it can be registered from a Razor Pages page model or an MVC controller. This technique is useful for separating C# logic from Razor files.

Constructor injection is used to access an instance of ITagHelperComponentManager. The Tag Helper Component is added to the instance's Tag Helper Components collection. The following Razor Pages page model demonstrates this technique with AddressTagHelperComponent:

[!code-csharp]

In the preceding code:

  • Constructor injection is used to access an instance of ITagHelperComponentManager.
  • An instance of AddressTagHelperComponent is added to the app's Tag Helper Components collection.

Create a Component

To create a custom Tag Helper Component:

  • Create a public class deriving from xref:Microsoft.AspNetCore.Mvc.Razor.TagHelpers.TagHelperComponentTagHelper.
  • Apply an [HtmlTargetElement] attribute to the class. Specify the name of the target HTML element.
  • Optional: Apply an [EditorBrowsable(EditorBrowsableState.Never)] attribute to the class to suppress the type's display in IntelliSense.

The following code creates a custom Tag Helper Component that targets the <address> HTML element:

[!code-csharp]

Use the custom address Tag Helper Component to inject HTML markup as follows:

public class AddressTagHelperComponent : TagHelperComponent
{
    private readonly string _printableButton =
        "<button type='button' class='btn btn-info' onclick=\"window.open(" +
        "'https://binged.it/2AXRRYw')\">" +
        "<span class='glyphicon glyphicon-road' aria-hidden='true'></span>" +
        "</button>";

    public override int Order => 3;

    public override async Task ProcessAsync(TagHelperContext context,
                                            TagHelperOutput output)
    {
        if (string.Equals(context.TagName, "address",
                StringComparison.OrdinalIgnoreCase) &&
            output.Attributes.ContainsName("printable"))
        {
            var content = await output.GetChildContentAsync();
            output.Content.SetHtmlContent(
                $"<div>{content.GetContent()}</div>{_printableButton}");
        }
    }
}

The preceding ProcessAsync method injects the HTML provided to xref:Microsoft.AspNetCore.Razor.TagHelpers.TagHelperContent.SetHtmlContent* into the matching <address> element. The injection occurs when:

  • The execution context's TagName property value equals address.
  • The corresponding <address> element has a printable attribute.

For example, the if statement evaluates to true when processing the following <address> element:

[!code-cshtml]

Additional resources

  • xref:fundamentals/dependency-injection
  • xref:mvc/views/dependency-injection
  • xref:mvc/views/tag-helpers/builtin-th/Index