Back to the blog

HTL- Mightier than JSP and why you must switch to it now

author image

Akshay Rathnavas

Technology | December 03, 2019

hero image

Adobe introduced HTL (formerly known as Sightly) to provide a better and more segregated use of front-end templating. The name Sightly came after the fact that it means “pleasing to the eyes”.

JSP (JavaServer Pages) on the other hand can be used to write any and all Java code. For a lot of people this seems to be a powerful way to achieve front-end logic since Java, being a server-side language has better flexibility and features. The possibility being limitless, people stick to the legacy JSP over Sightly. But Adobe recommends HTL because of its many benefit. This article would try to explain some of them, as well as document some use-cases in HTL.


One of the main reason for introducing HTL is to circumvent the use of explicit XSS Protection.

Cross Site (XSS ) Scripting

Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites


Consider this seemingly harmless looking URL"abc"

Any query parameter, especially if used inside the page to display can have a script injected into it.


This will expose any information that is not primarily meant to be exposed.

In JSP we use <p>${fn:escapeXml(string1)}</p> to prevent any XSS Exploitation. But in HTL, this is done automatically without any programmer intevention.

Context-Aware Escaping

HTL provides the proper context-aware escaping to all variables being output to the front-end. Example: You have a variable in HTL, description and

description= "<p> this is a sample text </p> <ul> <li>List 1</li><li> List 2</li></ul>"

If you output this in JSP, you would get the result exactly like the text. But in HTl, you can use context specific escaping that intelligently escapes there according to your requirement like below.

${description @ context='html'}

This gives the output: this is a sample text

  • List 1
  • List 2

Explicit context must be set for style contexts:

<span style="color: ${properties.color @ context='styleToken'};">...</span>

Explicit context must be set for script contexts:

<span onclick="${properties.function @ context='scriptToken'}();">...</span>

Escaping and XSS protection can also be turned off:

<div>${myScript @ context='unsafe'}</div>

Easier Front-end Development with Separation of Concerns

It is not easy for a core front-end developer to code in JSP especially when it has got several scriptlets. This is also one of the reason that HTL was introduced, the proper segregation of back-end and front-end logic.

There need not be any dependency with the back-end development team for any task to be completed. This has been made simpler with the help of the JavaScript Use-API. Java services too can be referenced, but in JavaScript, which is a familiar territory for the front-end developers. All that matters is the returned values from the service with which the further manipulation/ logic implementation can be done.

Separation of concerns defines the separation of the front-end from the business logic in different files

Hence, with multiple files for the business logic, the files are not only reusable, but also aids in better coding and maintainability of the code. Templates used in HTL are usually reusable too.

Powerful Use-API for Accessing Logic

It is mentioned in the title that HTL is mightier than JSP. So, everyone unfamiliar with HTL would be wondering as to how it is possible, when JSP sports the ability to use Java within itself. Here comes the Use-API

There are two types of Use-APIs

  • Java Use-API
  • JavaScript Use-API

How to implement Use-API?

Use-API is typically used, when you have to use any server-side service or perform any server-side task, but, in the front end.

  • Create a normal .java file or a .js file as a sibling of your “.html” HTL file. (It can also be referenced from any other path)
  • For a Java file, the class should implement WCMUsePojo, or have any class that internally implements the WCMUsePojo (like SlingModels)
  • For a JavaScript file, the entire file should be enclosed by use(function() { // your logic here; })
  • For either of the above methods, write your logic, and return the desired output to be used on the client-side.

Better and Neater Syntax

Consider the following JSP Syntax

<%@include file=”/libs/foundation/global.jsp”%><% %>
<%@page session=”false” %>
<cq:includeClientLib css=”test.css” />
<cq:includeClientLib js=”test.js” />
String title = properties.get(“jcr:title”, “default title”);
String text = properties.get(“jcr:text”, “default text”);

Title: <%= currentPage.getTitle() %><br>
Name: <%= currentPage.getName() %><br>
Path: <%= currentPage.getPath() %><br>

The same in HTL would be written as follows:

<sly data-sly-use.clientlib=”/libs/granite/sightly/templates/clientlib.html” data-sly-call=”${clientlib.js @ categories=’clientlib1′}” data-sly-call=”${clientlib.css @ categories=’clientlib1′}” >
<div data-sly-include script=”/libs/foundation/global.jsp”>

<p>Title: ${}</p>
<h3>Page Details</h3>
<p>Title: ${currentPage.Title}</p>
<p>Name: ${currentPage.Name}</p>
<p>Path: ${currentPage.Path}</p>

Compatibility with JSP (Components)

Majority of the people who didn’t incorporate HTL into their projects, fear that the components might stop working or break on using HTL altogether. But Adobe has provided a (backward) compatibility, so that HTL can use JSP components too. Example:

 <sly data-sly-resource="${'par1' @ resourceType='projectname/components/content/foldername/componentname'}"/>

where projectname/components/content/foldername/componentname points to a JSP component.

P.S. Similar syntax can include HTL component too.

Additional Features/ Perks

Sightly provides list iteration and repeating with simpler syntaxes.

<div data-sly-repeat="${obj.values}">
<div data-sly-list="${obj.values}">

Provides i18n: Internationalization

i18n is provided with handy features, see below.

${'Sample Input String' @ i18n, locale='en-US', hint='Sample Hint'}

Array Join: Implode Functions

We can manipulate the output of an array object by providing a custom separator string.

${['apples', 'oranges'] @ join='-- '} <!--/* outputs: apples;--oranges*/-->

Reduced Costs

Increased security, simplified development and improved team collaboration, translates for AEM projects in reduced effort, faster time to market (TTM), and lower total cost of ownership (TCO).

Concretely, from what has been observed when re-implementing the site with the HTML Template Language is that the cost and duration of the project could be reduced by about 25%.


Miscellaneous Features

  • Similar to JSP you can call any back-end functions including OSGI Services using the inbuilt functions provided with HTL. Some inbuilt functions are listed below.
currentNode    --> javax.jcr.Node
currentSession --> javax.jcr.Session
log            --> org.slf4j.Logger
out            -->
properties     -->
reader         -->
request        -->
resolver       -->
resource       -->
response       -->
sling          -->
  • Some additional use-cases for JavaScript Use-API
example.title =["jcr:title"];
var difference = org.apache.commons.lang.StringUtils.difference(cat, dog);
example.title = properties.get("jcr:title");
example.title = properties.get("jcr:title", "Hello World"); // Example - Set default value

Till date, there wasn’t a use-case in JSP that could not be translated to HTL. And with the additional benefits, it’s long overdue for a complete revamp of your code-base from JSP to HTL, if its not been done already.


The below are the references for this article, along with a few link(s) for further reading.

Browse all categories