3.2 HTL (HTML Template Language) Block Statements & Context-Aware Escaping

Key Takeaways

  • HTL enforces strict separation of markup and business logic by eliminating scriptlets, relying on data-sly-use to bind Sling Models and Java Use-API objects.
  • data-sly-resource triggers Sling Resource Resolution to render child or synthetic resources, whereas data-sly-include directly executes a local script without changing resource context.
  • HTL iteration statements provide automatic loop status metadata: itemList.index (0-based), itemList.count (1-based), itemList.first, itemList.last, itemList.odd, and itemList.even.
  • HTL provides automatic context-aware XSS escaping by analyzing the HTML AST, applying appropriate sanitization for HTML body, attributes, URIs, and scripts.
  • The context='unsafe' display context disables all security sanitization; its use on untrusted user-supplied input creates severe Cross-Site Scripting vulnerabilities.
Last updated: September 2026

3.2 HTL (HTML Template Language) Block Statements & Context-Aware Escaping

Exam Focus: HTL (HTML Template Language, formerly known as Sightly) is the mandatory templating engine for modern Adobe Experience Manager development. The AD0-E128 exam tests your deep understanding of HTL block statements (data-sly-use, data-sly-resource, data-sly-include, data-sly-test, data-sly-list, data-sly-repeat, data-sly-template, data-sly-call, data-sly-attribute, data-sly-element), built-in iteration metadata (index, count, first, last, odd, even), DOM unwrap mechanics with <sly>, and context-aware XSS escaping (context='html', context='attribute', context='uri', context='scriptString', context='unsafe').


HTL Design Principles & Architectural Philosophy

In legacy AEM development, views were constructed using JavaServer Pages (JSP). JSPs permitted developers to embed raw Java scriptlets (<% ... %>) directly alongside HTML markup. This practice introduced severe architectural flaws:

  • Tight Coupling: Complex business logic, database queries, and repository writes leaked into the presentation layer.
  • Severe Security Vulnerabilities: Developers frequently forgot to apply manual HTML entity escaping, creating widespread Cross-Site Scripting (XSS) vulnerabilities.
  • Unmaintainability & Poor Tooling: Front-end developers could not easily read, preview, or edit JSPs without a running local AEM server.

HTL was engineered from the ground up to solve these problems by adhering to two strict tenets:

  1. Strict Separation of Concerns: HTL contains zero support for raw Java or procedural scripting code. Presentation templates define only markup and data placeholders. All computation, business logic, data normalization, and backend calls must reside in backend Java (primarily Sling Models).
  2. Security by Default: HTL parses the HTML Abstract Syntax Tree (AST) at compile time. It automatically identifies the structural context of every dynamic expression and applies the appropriate context-aware output escaping to prevent XSS.
  3. Valid HTML5 Markup: Every HTL statement is expressed as a standard HTML5 data-sly-* attribute or a synthetic <sly> tag. Templates remain valid HTML documents that can be parsed and styled by standard front-end design tools.

HTL Block Statements in Depth

HTL block statements are evaluated server-side by the Sling HTL compiler. Below is an exhaustive technical breakdown of each statement.

1. data-sly-use: Binding Backend Logic

The data-sly-use statement initializes and binds a backend logic provider to a local template variable.

<!-- Binding a Sling Model -->
<div data-sly-use.hero="com.myproject.core.models.HeroBannerModel"
     class="hero-banner">
    <h1>${hero.title}</h1>
    <p>${hero.description}</p>
</div>

HTL supports three distinct Use-API backends:

  • Sling Models (Recommended): The class is automatically adapted from the current Resource or SlingHttpServletRequest.
  • Java Use-API (WCMUsePojo or org.apache.sling.scripting.sightly.pojo.Use): Legacy POJO-based approach where the class implements lifecycle methods.
  • JavaScript Use-API: Server-side JavaScript files located in the component directory (evaluated via the Rhino/Nashorn engine; deprecated for enterprise production).

Passing Parameters via data-sly-use

HTL allows passing dynamic parameters into Sling Models via expression options:

<div data-sly-use.card="${'com.myproject.core.models.CardModel' @ title=properties.customTitle, theme='dark'}">
    <p class="theme-${card.theme}">${card.title}</p>
</div>

Inside the Java Sling Model, these parameters are captured using the @RequestAttribute injector:

@Model(adaptables = SlingHttpServletRequest.class)
public class CardModel {
    @RequestAttribute(name = "theme")
    private String theme;
    
    @RequestAttribute(name = "title")
    private String title;
    
    // getters...
}

2. data-sly-resource: Including Child and Synthetic Resources

The data-sly-resource statement includes the rendering result of another JCR resource by triggering the full Apache Sling Resource Resolution pipeline.

<!-- Including an existing child resource -->
<div data-sly-resource="${'image' @ resourceType='myproject/components/content/image'}"></div>

<!-- Including with selectors and wrapper tag configuration -->
<div data-sly-resource="${'teaser' @ resourceType='myproject/components/content/teaser', 
                                selectors='featured', 
                                decorationTagName='section', 
                                cssClassName='featured-teaser'}"></div>

Common data-sly-resource options:

  • resourceType: Overrides or explicitly sets the component used to render the target resource (essential when rendering synthetic child resources).
  • selectors: Passes one or more selectors to the Sling request (e.g., selectors=['card', 'compact']).
  • decorationTagName: Specifies the wrapper HTML tag generated by AEM (pass empty string '' to strip the wrapper tag entirely).
  • cssClassName: Appends custom CSS classes to the AEM decoration wrapper tag.
  • wcmmode: Overrides authoring mode for the included resource (e.g., wcmmode='disabled').

3. data-sly-include: Direct Script Inclusion

The data-sly-include statement directly executes and includes another script file located within the same component hierarchy:

<sly data-sly-include="header.html" />

Critical Difference: data-sly-resource vs data-sly-include

Featuredata-sly-resourcedata-sly-include
Sling Request CycleInvokes full Sling Resource Resolution on a JCR path.Directly executes a script file in the current component folder.
Resource ContextSwitches context: resource points to the target resource node.Preserves context: resource and properties remain pointing to the current component.
Sling ModelsInstantiates a fresh Sling Model adapted to the child resource.Continues using the current component's Sling Model.
Primary Use CaseRendering child components, synthetic sub-nodes, or layout containers.Breaking down a monolithic component template into modular sub-templates.

4. data-sly-test: Conditional Rendering & Variable Definition

The data-sly-test statement conditionally renders the host element based on the truthiness of an expression:

<div data-sly-test="${properties.ctaUrl}">
    <a href="${properties.ctaUrl}">Learn More</a>
</div>

Truthiness Rules in HTL

An expression evaluates to false if the value is:

  • null
  • Boolean false
  • Empty string ""
  • Numeric 0
  • Empty array, Collection, or Map

Everything else evaluates to true.

Setting Reusable Variables

By appending an identifier (e.g., data-sly-test.hasTitle), HTL saves the boolean outcome into a scoped variable:

<sly data-sly-test.hasTitle="${properties.jcr:title}" />
<div class="header" data-sly-test="${hasTitle}">
    <h1>${properties.jcr:title}</h1>
</div>

5. data-sly-list and data-sly-repeat: Iteration & Loop Variables

Both statements iterate over Collections, Arrays, Iterators, and Maps. However, they handle host HTML elements differently:

  • data-sly-list: Renders the host element once as an outer container, repeating only its inner child elements.
  • data-sly-repeat: Duplicates the host element itself for every item in the collection.
<!-- data-sly-list: <ul> rendered once, <li> repeated -->
<ul data-sly-list.item="${model.navigationItems}">
    <li>${item.title}</li>
</ul>

<!-- data-sly-repeat: <div> repeated for every article -->
<div data-sly-repeat.article="${model.articles}" class="article-card">
    <h2>${article.title}</h2>
</div>

Built-in Loop Metadata Variables

When iterating with data-sly-list.item (or data-sly-repeat.item), HTL automatically creates an iteration status object named <variable>List (e.g., itemList):

Loop PropertyTypeDescription
itemList.indexint0-based counter of the current iteration (0, 1, 2, ...).
itemList.countint1-based counter of the current iteration (1, 2, 3, ...).
itemList.firstbooleantrue if this is the first item in the collection (index == 0).
itemList.lastbooleantrue if this is the final item in the collection.
itemList.oddbooleantrue if count is odd (1, 3, 5, ...).
itemList.evenbooleantrue if count is even (2, 4, 6, ...).

Example utilizing loop status:

<ul data-sly-list.slide="${carousel.slides}">
    <li class="slide ${slideList.first ? 'active' : ''} ${slideList.even ? 'row-even' : 'row-odd'}">
        <span>Slide ${slideList.count} of ${carousel.slides.size}</span>
        <h3>${slide.title}</h3>
    </li>
</ul>

6. data-sly-template and data-sly-call: Reusable Template Macros

HTL templates function as parameterized HTML macros:

<!-- Defining a template macro -->
<template data-sly-template.button="${@ text, linkUrl, variant}">
    <a href="${linkUrl}" class="btn btn-${variant || 'primary'}">${text}</a>
</template>

<!-- Calling the template in the same file -->
<sly data-sly-call="${button @ text='Subscribe', linkUrl='/subscribe', variant='secondary'}" />

Templates can also be imported from external files:

<sly data-sly-use.lib="buttonLibrary.html"
     data-sly-call="${lib.button @ text='Contact Us', linkUrl='/contact'}" />

7. data-sly-attribute, data-sly-element, and <sly>

  • data-sly-attribute: Dynamically adds, updates, or removes attributes. If an attribute evaluates to false, null, or "", HTL omits the attribute entirely from the rendered DOM.
  • data-sly-element: Dynamically switches the HTML tag name (e.g., changing <p> to <h2> based on author configuration: <h1 data-sly-element="${properties.headingTag || 'h2'}">${properties.title}</h1>).
  • <sly>: A synthetic element used solely to hold HTL block statements. In the rendered HTML output, the <sly> tag is completely unwrapped and removed, leaving only its contents in the DOM.

Context-Aware XSS Escaping & Display Contexts

Cross-Site Scripting (XSS) occurs when malicious JavaScript is injected into web pages viewed by other users. HTL prevents XSS by parsing the HTML markup into an Abstract Syntax Tree (AST) and automatically applying context-aware encoding based on where the dynamic expression appears in the markup.

<!-- Automatically escaped as HTML Body content (context='text') -->
<p>${properties.title}</p>

<!-- Automatically escaped as an HTML Attribute value (context='attribute') -->
<input type="text" value="${properties.authorName}" />

<!-- Automatically validated as a safe URI (context='uri') -->
<a href="${properties.linkUrl}">Visit</a>

Comprehensive Display Contexts Reference

Developers can explicitly override the automatic escaping context using the @ context='...' option:

Display ContextDescription & Escaping BehaviorTypical Use Case
context='text'Default for HTML element bodies. Converts special characters (<, >, &, ", ') into HTML entities (&lt;, &gt;, etc.).Outputting plain text titles, author names, descriptions.
context='html'Passes markup through AEM's AntiSamy / XSS Protection API. Preserves safe HTML formatting tags (<p>, <b>, <a>) while stripping dangerous tags (<script>, <iframe>) and event handlers (onload, onclick).Outputting Rich Text Editor (RTE) authored content.
context='attribute'Escapes quotation marks and special characters to ensure text cannot break out of an HTML attribute delimiter.Outputting dynamic values into data-*, aria-*, or title attributes.
context='uri'Validates protocol schemes (permits http, https, mailto, tel; strictly blocks javascript:, vbscript:, data:) and percent-encodes unsafe URI characters.Outputting dynamic URLs in <a href="..."> or <img src="...">.
context='scriptString'Escapes quotation marks, newlines, and control characters for safe insertion inside a JavaScript string literal inside <script> tags.Emitting a string variable into an inline JavaScript snippet.
context='styleToken'Validates a single CSS token such as an identifier.Outputting a controlled CSS token; use styleString for a full style declaration string.
context='number'Emits a value only in a numeric context when it can be represented safely as a number.Emitting numeric values in markup or data attributes.
context='unsafe'Disables all escaping and sanitization entirely. Emits raw bytes directly to the HTTP response stream.Extreme Caution: Rendering trusted, pre-compiled SVG assets or trusted server-side HTML.

Critical Security Exam Warning: context='unsafe' Hazards

Exam Trap: Any question asking how to render user-supplied input, query parameters, or arbitrary author text must never use context='unsafe'. Using context='unsafe' on unvalidated input creates an immediate, critical XSS vulnerability. Static analysis may report unsafe rendering patterns, but the decisive rule is architectural: never render untrusted input with context='unsafe'; validate or remove the need for raw output.

Test Your Knowledge

In an HTL template iterating over a list of carousel slides using data-sly-list.slide="${model.slides}", which expression evaluates to a 1-based numerical counter (1, 2, 3...) of the current iteration?

A
B
C
D
Test Your Knowledge

An AEM component renders rich-text content authored via a Rich Text Editor (RTE) dialog field that includes allowed HTML tags such as <p>, <strong>, and <a>. Which HTL expression ensures the markup is rendered as HTML in the browser while filtering out malicious scripts?

A
B
C
D
Test Your Knowledge

How does data-sly-repeat differ from data-sly-list when iterating over a collection in HTL?

A
B
C
D
Test Your Knowledge

What is the primary architectural difference between data-sly-resource and data-sly-include in HTL component development?

A
B
C
D