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 |
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)
Two common use cases of Tag Helper Components include:
The following sections describe these use cases.
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:
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.
The body
Tag Helper Component can inject a <script>
element into the <body>
element. The following code demonstrates this technique:
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:
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.
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
- Registration via Razor file
- Registration via Page Model or controller
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:
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
:
In the preceding code:
- The
@inject
directive provides an instance ofITagHelperComponentManager
. The instance is assigned to a variable namedmanager
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:
The provided markup
parameter is used in ProcessAsync
as follows:
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
:
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.
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:
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 equalsaddress
. - The corresponding
<address>
element has aprintable
attribute.
For example, the if
statement evaluates to true when processing the following <address>
element:
- xref:fundamentals/dependency-injection
- xref:mvc/views/dependency-injection
- xref:mvc/views/tag-helpers/builtin-th/Index