AEM Insider
EP09 // AEM Complete Tutorial Series 2026

It ends in .html —
but it isn't HTML. It's HTL.

also known as Sightly
The ${…} expression · the objects it reads · operators · contexts · options
${…}escaped by defaultPart 1 of 2
aeminsider.com · @aeminsider · Not affiliated with Adobe Inc.
// Chapter 01 · You already know more HTL than you think

You've used it in every episode.

EP04

${properties.title}

Read a dialog value.

EP05

${item.text @ context='html'}

Render rich text safely.

EP08

${clientlib.css @ categories='…'}

Call a template.

Every one is the same handful of parts: an expression, an object, sometimes an operator, sometimes an option after the @. Today we name them all.
// Chapter 02 · Anatomy of an expression

The ${…} expression.

${ properties.name }
${ }

the delimiter

properties

an object HTL gives you

.name

a member of it

Literals
${'a string'} ${42} ${true} ${[1, 2, 'three']}
Access
${obj.key} // dot ${obj['key']} ${obj[keyVar]} ${arr[0]}
It runs on the server. The output is plain HTML. The browser never sees ${…}.
// Chapter 03 · The objects HTL hands you

You don't just get properties.

propertiesthis component's own values (a ValueMap)${properties.name}
resourcethe current Sling resource${resource.path}
currentNodethe raw JCR node${currentNode.name}
pagePropertiesthe page's properties${pageProperties['jcr:title']}
inheritedPagePropertiessame, but walks UP to an ancestor${inheritedPageProperties.brandColor}
currentPagethe Page object${currentPage.title}
wcmmodeedit / preview / disabled — author vs publish${wcmmode.edit}
componentcurrentSessionrequestlog — also bound for free
properties IS resource.valueMap — one node, two views. properties = the component. pageProperties = the page. Different nodes.
// Chapter 04 · Operators

Combine and compare — inside the braces.

Logic
||OR / defaultrole || 'Team member'
&&AND
!NOT
( )grouping — controls precedence
? :ternaryfeatured ? 'A' : 'B'
Compare — strict, no type conversion
== !=equal / not equal
< <=less than
>= >greater thanrating >= 4

Works on strings, numbers, booleans, null, and Java enums.

Precedence: ( ) → ! → && → || → ? :. Spaces are required around ?, : and @.
// Chapter 05 · Escaped by default

HTL escapes every expression — automatically.

An author types into a field
<b>hi</b> <script>steal()</script>
→
The page shows
<b>hi</b> <script>steal()</script>
JSP made you remember to escape. HTL makes you remember to un-escape.
// Chapter 06 · The contexts, in one place

Pick where the value lands.

In an element
textdefault

escapes all HTML

html

safe rich markup, filtered

number

integers — 0 if it fails

In an attribute
attributedefault

escapes attribute characters

uridefault

for href / src — validates; nothing if unsafe

In a script or style
scriptString

inside a JS string

scriptToken

a JS identifier or number

styleString

inside a CSS string

styleToken

a CSS value

context is itself an option — the one that matters most. attributeName / elementName belong to data-sly-attribute / data-sly-element → Part 2.
// Chapter 07 · Inside a script or a style block

Two more places a value can land.

<script>
var user = "${properties.name @ context='scriptString'}";

Escapes quotes and breakouts — the value stays a string. scriptToken is for a bare identifier or number.

<style>
.cmp-profile {
  color: ${properties.brandColor @ context='styleToken'};
}

Validates a CSS value — outputs nothing if it isn't one. styleString is for inside a CSS string.

There is also unsafe — it turns escaping OFF completely. If you ever type it, stop and find another way.
// Chapter 08 · Options: shape the value with @

Two options you'll use constantly.

@ join

${properties.tags @ join=' · '}

beforeone,two,three
afterone · two · three

An array → a string, with your separator.

@ format

${'yyyy-MM-dd HH:mm' @ format=properties.published}

beforea raw date
after2026-08-22 14:30

A date → text, in your pattern.

join, format, context — one family, all after the @. Two shape the value; one keeps it safe.
// Chapter 09 · Expressions, in one page

Everything in ${…}, at a glance.

Objectsproperties · resource · currentNode · pageProperties · inheritedPageProperties · currentPage · wcmmode
Operators|| · && · ! · ( ) · ? : · == != < <= >= >
Contextstext · html · number · attribute · uri · scriptString · styleToken
Options@ join · @ format
// Next on AEM Insider

Next: HTL, Part 2

The block statements. data-sly-use to bring in logic, data-sly-test to show or hide, data-sly-list to loop, data-sly-resource / -include to compose, data-sly-template to reuse. The attributes that build the markup we've been filling with expressions.

EP10 · data-sly-*