In Asp.Net Core it is possible to create custom tag helpers that nests within other custom tag helpers. Consider the following example borrowed from another interesting post:
modal-footer are custom tag helpers, the
modal tag helper encapsulates all the verbose html of the bootstrap modal. The
modal-body and the
modal-footer tag helpers allows the programmer to respectively specify the content of the modal’s body and footer.
modal-footer are tag helpers created to be used only inside the
modal tag helper.
In this post we are going to see as usual a very basic example that will show how to create nested tag helpers.
How nested tag helpers work?
We are going to create two tag helpers:
ChildTagHelper is going to be nested inside
ParentTagHelper. The following is the typical usage example:
<parent> <child></child> </parent>
Now let’s see how the two tag helpers are defined:
ParentTagHelper.ProcessAsync method performs the following steps:
- Create an instance of the
ParentChildContextclass which will act as a data transfer object between the parent and child tag helpers
- Register the
ParentChildContextinstance in the context argument
- Await the rendering of it’s children content
- When the children’s content is available, set the output content by using data in the
ParentChildContextinstance populated by the
Notice here how the
ParentTagHelper creates the
ParentChildContext instance (
parentChildContext) and sets it to be passed to it’s nested tag helpers (
child in our case) by adding the instance to the
In fact, the
context argument in the
TagHelper.Process method is used to pass data between parent and child tag helpers; Items in the
context.Items dictionary are made available to the nested tag helper’s
ChildTagHelper exhibits a slightly different
Process behavior compared to usual tag helpers; the content it generates is not passed to the
output argument, it is instead passed to the
ParentChildContext instance. Furthermore the output is forced to be suppressed with the
The parent tag helper relies on the previously described child behavior to get the content generated by the nested tag helpers. The parent is then responsible for assembling the final content that is going to be rendered in the razor view.
ParentTagHelper class is slapped with the
[RestrictChildren] attribute that allows to specify the children tags that can be nested inside the parent tag helper.
Why defining a custom context?
In the previous example the
ParentChildContext class as been created so that its instances act as data transfer objects.
This is necessary as we cannot rely on
context.Items to pass data from child to parent. This inability is due to the fact that the
TagHelperContext instance (
context argument) passed to the child tag helper is actually a copy of the
context available in the parent tag helper.
This means that modifications on the
context.Items dictionary in the child tag helper does not affect the
context.Items in the parent tag helper.
On the flip side, objects referenced by the parent’s
context.Items dictionary are available in the child’s
context.Items, so we basically do as in
ParentTagHelper.ProcessAsync; we create a custom context, register in
context.Items and then it can be used by the parent tag helper and its children.