HomeGuidesAPI Reference
Submit Documentation FeedbackJoin Developer CommunityOptimizely GitHubOptimizely NuGetLog In

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) version12 did not initially include support for tag helpers since initial release. Tag helpers are a popular alternative for developers, especially when implementing a new site based on CMS 12.

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

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

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

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 item).
  • epi-on-item-rendered – Specify the method name which will be executed after the html output of content are item has been 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 supported built-in properties:

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

Examples:

The following steps show how to use this feature:

  1. Install the EPiServer.CMS.AspNetCore.TagHelpers package.
  2. Create a content type like 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
}
  1. Specify model in view: ~/Views/MyPage/Index.cshtml
@model MyPage
  1. Register dependencies in Startup.cs.
services.AddCmsTagHelpers();
  1. To make the tag helpers available to all our 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 example

<span epi-property="CategoryList" />

HTML output in view mode:

<span>Category1,Category2</span>

ContentReference example

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 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 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 example

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 example

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 example

📘

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 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 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 example

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 example

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 example

The same for XhtmlString , it could be rendered by writing

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

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

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

Block example

You can specify template tag when rendering 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 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 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 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.