the statement
a name you choose — optional
what it works on
same options as Part 1
It sits on an element — and that element is its scope.
The attribute is removed from the output. Always.
<sly> is a tag that removes itself — a place to put a statement.
<p data-sly-test="${properties.featured}"> Featured </p>
Falsy → the element and everything inside it is never written. Not hidden with CSS — view source, and the paragraph is not there at all.
<p data-sly-test.isFeatured="${properties.featured}"> Featured </p> <p data-sly-test="${!isFeatured}"> Not featured </p>
HTL has no else. Name the answer, then test the opposite.
<p data-sly-test="${wcmmode.edit}">Authors only</p> — the element exists only inside the editor. Part 1 showed you the value. Here it does the work.
<ul data-sly-list.tag="${properties.tags}"> <li>${tagList.count}. ${tag}</li> </ul>
Repeats what is inside the element. One <ul>, many <li>.
<span data-sly-repeat.tag="${properties.tags}"> ${tag} </span>
Repeats the element itself. Many spans, no wrapper at all.
<a data-sly-attribute.href="${properties.link}" data-sly-attribute.title="${properties.role}">
<h2 data-sly-element="${properties.headingLevel}"> ${properties.name} </h2>
attributeName checks a dynamic attribute name is safe. elementName checks a dynamic tag name against the allowed list. You don't type them — these two statements apply them for you. That is where they live.
<sly data-sly-include="meta.html"></sly>
A file. Same node, same properties. The name resolves through the super-type chain — EP07.
<sly data-sly-resource="${'/content/…/htl-blocks/…/container/card'}"></sly>
A node. New resource, new properties. EP07's ladder runs again, from that node.
<template data-sly-template.skillrow="${@ name, level}"> <li>${name} — ${level}</li> </template> // renders nothing until it is called
<sly data-sly-call="${skillrow @ name='HTL', level='Confident'}"></sly>
<sly data-sly-use.lib="lib.html"></sly> <sly data-sly-call="${lib.skillrow @ name=…, level=…}"></sly>
A Sling Model — typed values instead of reaching into raw properties. That is the clean answer to everything we have worked around so far, and it is the next episode.
<ul data-sly-use.lib="lib.html" data-sly-test="${properties.featured}" data-sly-list.tag="${properties.tags}"> <li>${tag}</li> </ul>
data-sly-use can load a Java class. Typed values instead of raw properties — the @Model annotation, @ValueMapValue, adapting a resource. The end of every "fine for learning, not how real projects ship it" in this series.