HomeDev GuideAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunitySubmit a ticketLog In
GitHubNuGetDev CommunitySubmit a ticket

Render properties with tag helpers

Tag Helpers were introduced in ASP.NET Core as an alternative to HTML helpers for rendering HTML in Razor views. Optimizely Content Management System (CMS) version 12 did not initially include support for tag helpers because of the initial release. Tag helpers are a popular alternative for developers, especially when implementing a site based on CMS 12.

Developers can build coupled sites using Razor views with tag helpers and CMS content. Tag helpers help you:

  • Reduce the amount of developer training required to build sites on the CMS.
  • Help customers get maximum value from improvements to .NET from MS
  • Moving rendering decisions closer to the HTML canvas makes it easier for front-end engineers to take control of the markup or output in the front end.
  • Easier to customize the output.
  • Keep the code clean and more intuitive.
  • Work with OPE by default.

When working with attribute helpers, developers can specify a page model using standard .NET API and get type-aware Intellisense for CMS pages.

Supported property attribute tag helpers

  • epi-property – Render content property from the model as inner HTML or attributes depending on the element it's added to.
  • epi-property-item – Render an element for each child object in a collection (currently only supported for content area items).
  • epi-on-item-rendered – Specify the method's name that is executed after the HTML output of the content item is written.
  • epi-template-tag – Specify which tag should be applied when resolving the actual template.
  • required-client-resources – Render client resources by using tag helpers.

Tag helpers support the same number of HTML elements and generate the same HTML output as the Html.PropertyFor does. Tag helpers should support built-in properties:

  • CategoryList
  • ContentArea
  • ContentData
  • ContentReferenceList
  • ContentReference
  • LinkItemCollection
  • LinkItem
  • Url
  • XhtmlString
  • DateTime
  • Int
  • Double
  • Boolean
  • String
  • LongString
  • Weekday

The following steps show how to use this feature:

  1. Install the EPiServer.CMS.AspNetCore.TagHelpers package.

  2. Create a content type like the following:

    [ContentType]
    public class MyPage: PageData {
      public virtual CategoryList CategoryList {
        get;
        set;
      }
      public virtual ContentArea ContentArea {
        get;
        set;
      }
      public virtual IList < ContentReference > ContentReferenceList {
        get;
        set;
      }
      public virtual ContentReference ContentReference {
        get;
        set;
      }
      public virtual ContentReference TargetPage {
        get;
        set;
      }
    
      [UIHint(UIHint.Image)]
      public virtual ContentReference Image {
        get;
        set;
      }
      public virtual PageReference PageReference {
        get;
        set;
      }
      public virtual LinkItem LinkItem {
        get;
        set;
      }
      public virtual LinkItemCollection LinkItemCollection {
        get;
        set;
      }
      public virtual Url Url {
        get;
        set;
      }
      public virtual XhtmlString XhtmlString {
        get;
        set;
      }
      // other properties
    }
    
  3. Specify the model in view: ~/Views/MyPage/Index.cshtml.

    @model MyPage
    
  4. Register dependencies in Startup.cs.

    services.AddCmsTagHelpers();
    
  5. To make the tag helpers available to Razor views, add the addTagHelper directive to the Views/_ViewImports.cshtml file:

    @addTagHelper *, EPiServer.Cms.AspNetCore.TagHelpers
    

📘

NOTE

The following examples should work with OPE by default.

Category list examples

<span epi-property="CategoryList" />

HTML output in view mode:

<span>Category1,Category2</span>

ContentReference examples

With anchor (<a>) tag:

<a epi-property="ContentReference" />

HTML output in view mode

when target content is a page or routable content

<a href="/en/mytargetcontent/">My target content name</a>

when target content is non-routable content

<a>My target content name</a>

You could specify a value for attributes.

<a epi-property="ContentReference" href="https://custom.domain.com" data-custom-attribute="something" />

HTML output in view mode:

<a href="https://custom.domain.com" data-custom-attribute="something">My target content name</a>

You could provide custom text.

<a epi-property="ContentReference" href="https://custom.domain.com" data-custom-attribute="something">Custom text</a>

HTML output in view mode:

<a href="https://custom.domain.com" data-custom-attribute="something">Custom text</a>

With non-anchor (<a>) tag:

<span epi-property="ContentReference" />
<p epi-property="ContentReference" />

Output in view mode:

<span>My target content name</span>  
<p>My target content name</p>

With <img> tag:

<img epi-property="ContentReference" />

Output in view mode:

when the target content is an image

<img src="/globalassets/image.jpg" />

when target content is non-routable content

<img />

You could combine anchor (<a>) tag and <img> tag

<a epi-property="TargetPage" class='awesome'>
    <img epi-property="Image" class="image" alt="My Image" />
</a>

HTML output in view mode:

<a href="/en/target-page/" class='awesome'>
    <img src="/globalassets/image.jpg" class="image" alt="My Image" />
</a>

PageReference examples

With anchor (<a>) tag:

<a epi-property="PageReference" />

HTML output in view mode:

<a href="/en/target-page/">My target page name</a>

With non-anchor (<a>) tag:

<span epi-property="PageReference" />
<p epi-property="PageReference" />

Output in view mode:

<span>My target page name</span>  
<p>My target page name</p>

ContentReference list examples

With <ul> tag

<ul class="content-links" epi-property="ContentReferenceList" />

Example HTML output in view mode:

<ul class="content-links">
    <li>
        <a href="/en/alloy-track/" target="_blank" title="Link title">Link text</a>
    </li>
    <li>
        <a href="/globalassets/image.jpg" target="_blank" title="Image title">Image text</a>
    </li>
</ul>

The same with <ol> tag

<ol epi-property="ContentReferenceList" type="A" class="awesome-list" />

Example HTML output in view mode:

<ol type="A" class="awesome-list">
    <li>
        <a href="/en/alloy-track/" target="_blank" title="Link title">Link text</a>
    </li>
    <li>
        <a href="/globalassets/image.jpg" target="_blank" title="Image title">Image text</a>
    </li>
</ol>

📘

NOTE

Only HTML list ul and ol are supported. If other HTML tags are used, the output will look something like:

<div class="awesome" epi-property="ContentReferenceList" />
<div class="awesome">
    <a href="/en/alloy-track/">Alloy Track</a>
    <a href="/globalassets/image.jpg">Awesome image</a>
</div>

LinkItem examples

📘

NOTE

The HTML attribute target and title and link text are rendered based on values that is set in OPE. If the attributes and/or custom text is provided, those values would be used to render.

When a link item refers to a page.

<a epi-property="LinkItem" />

Output in view mode:

<a href="/en/alloy-plan/" target="_blank" title="Alloy Plan">Alloy Plan</a>

You could provide custom value for attributes.

<a epi-property="LinkItem" href="https://custom-link.com" title="Custom title" target="_parent"/>

Output in view mode:

<a href="https://custom-link.com" title="Custom title" target="_parent">Alloy Plan</a>

You could provide custom text.

<a epi-property="LinkItem" class="custom-class" title="Custom Title">Custom text</a>

HTML output in view mode:

<a href="/en/alloy-plan/" class="custom-class" title="Custom Title">Custom text</a>

When a link item refers to an image.

<img epi-property="LinkItem" />

Output in view mode:

<img src="/globalassets/image.jpg" title="My image" />

You could also specify values for attributes.

<img epi-property="LinkItem" src="https://custom-src.com" class="custom-class" title="Custom Title"/>

HTML output in view mode:

<img src="https://custom-src.com" class="custom-class" title="Custom Title"/>

LinkItemCollection examples

With <ul> tag

<ul epi-property="LinkItemCollection" class="awesome-list" />

Example HTML output in view mode:

<ul class="awesome-list">
  <li>
    <a href="/en/alloy-track/" target="_blank" title="Link title">Link text</a>
  </li>
  <li>
    <a href="/globalassets/image.jpg" target="_blank" title="Image title">Image text</a>
  </li>
</ul>

The same with <ol> tag

<ol epi-property="LinkItemCollection" type="A" class="awesome-list" />

Example HTML output in view mode:

<ol type="A" class="awesome-list">
  <li>
    <a href="/en/alloy-track/" target="_blank" title="Link title">Link text</a>
  </li>
  <li>
    <a href="/globalassets/image.jpg" target="_blank" title="Image title">Image text</a>
  </li>
</ol>

📘

NOTE

Only HTML list <ul> and <ol> are supported. If other HTML tags are used, the output will look something like:

<div class='awesome' epi-property="LinkItemCollection" />
<div class="awesome">
  <a href="/en/alloy-track/" target="_blank" title="Link title">Link text</a>
  <a href="/globalassets/image.jpg" target="_blank" title="Image title">Image text</a>
</div

URL examples

When URL refers to a page

<a epi-property="Url" class="awesome" />

HTML output in view mode:

<a href="/en/alloy-plan/" class="awesome">Alloy Plan</a>

When URL refers to an image

<img epi-property="Url" class="awesome" title='Awesome image' />

HTML output in view mode:

<img src="/globalassets/image.jpg" class="awesome" title="Awesome image" />

XhtmlString examples

The same goes for XhtmlString , it could be rendered by writing

<div id="xhtmlString" class="awesome" epi-property="XhtmlString" />

The HTML output is rendered based on string fragments that the XhtmlString consists of.

<div id="xhtmlString" class="awesome">
  <!-- Content of fragments -->
</div>

Block examples

You can specify a template tag when rendering the block.

<div id='TeaserBlock' class="awesome" epi-property="TeaserBlock" epi-template-tag="wide" />

HTML output:

<div id='TeaserBlock' class="awesome">
  <!-- Content of block template -->
</div>

ContentArea example

HTML markup:

<div epi-property="ContentArea" epi-template-tag="fullWidth" />

HTML output:

<div>
  <div>{{ContentAreaItem1_PlaceHolder}}</div>
  <div>{{ContentAreaItem2_PlaceHolder}}</div>
</div>

Custom template for content area item with epi-property-item attribute.

<div class="awesome" epi-property="ContentArea" epi-template-tag="wide">
  <p epi-property-item class="awesome" data-attribute="@attributes" />
</div>

HTML output:

<div class="awesome">
  <p class="awesome" data-attribute="@attributes">
    {{ContentAreaItem1_PlaceHolder}}
  </p>
  <p class="awesome" data-attribute="@attributes">
    {{ContentAreaItem2_PlaceHolder}}
  </p>
</div> 

The template can also be nested in multiple levels.

<div class="awesome" epi-property="ContentArea" epi-template-tag="wide">
  <div class="children-class">
    <p class="grand-children-class">
      <a epi-property-item class="content-area-item" />
    </p>
  </div>
</div>

HTML output:

<div class="awesome">
  <div class="children-class"> 
    <p class="grand-children-class">
      <a class="content-area-item"> 
        {{ContentAreaItem1_PlaceHolder}}
      </a>
    </p>
  </div>
  <div class="children-class"> 
    <p class="grand-children-class">
      <a class="content-area-item"> 
        {{ContentAreaItem2_PlaceHolder}}
      </a>
    </p>
  </div> 
</div> 

Use the extension method to customize the rendering process of content area item. Define a function in view like the following:

@functions {
  public void OnItemRendered(ContentAreaItem contentAreaItem, TagHelperContext context, TagHelperOutput output) {
    output.AddClass("customize-item", System.Text.Encodings.Web.HtmlEncoder.Default);
  }
}

And pass the function name as a value to epi-on-item-rendered attribute when rendering

<div class='content-area' epi-property="ContentArea">
  <p epi-property-item class="content-area-item" epi-on-item-rendered="OnItemRendered" />
</div>

Example HTML output:

<div class="content-area">
  <p class="content-area-item customize-item">{{ContentAreaItem1_PlaceHolder}}</p>
  <p class="content-area-item customize-item">{{ContentAreaItem2_PlaceHolder}}</p>
</div>

Render client resources example

You can render client resources by using Tag Helpers:

<required-client-resources area="Header" />

This is the same as @Html.RequiredClientResources("Header"). The default valid areas are Header and Footer.