HTL Tutorial #5: data-sly-text - Content Output

HTL Tutorial #5: data-sly-text - Content Output

What is data-sly-text?

data-sly-text is a block statement that replaces all content of an HTML element with the value of the expression.

Basic Syntax

<element data-sly-text="${expression}">
  This content will be replaced
</element>

Comparison with Inline Expressions

Inline Expression ${...}

<h1>${properties.title}</h1>

Output:

<h1>My Title</h1>

data-sly-text

<h1 data-sly-text="${properties.title}">
  Placeholder title
</h1>

Output:

<h1>My Title</h1>

Identical result, but with data-sly-text:

  • ✓ You can have a visible placeholder in edit mode
  • ✓ Clearer when the entire content is being replaced
  • ✓ Better compatibility with some preview tools

When to Use data-sly-text

1. Placeholders for Authors

In AEM edit mode, the author sees the placeholder:

<h2 data-sly-text="${properties.subtitle}">
  [Insert a subtitle here]
</h2>

In Edit Mode: Sees [Insert a subtitle here] In Published: Sees the actual value from properties.subtitle

2. Complete Element Content

When the element contains ONLY the expression:

<!-- Clearer with data-sly-text -->
<p data-sly-text="${properties.description}"></p>

<!-- Equivalent but less explicit -->
<p>${properties.description}</p>

3. HTML5 Compatibility

Some HTML preview tools don't recognize ${...}:

<!-- Better for static preview -->
<span data-sly-text="${user.name}">User Name</span>

<!-- ${user.name} might not work in some tools -->
<span>${user.name}</span>

Practical Examples

Example 1: User Card

<div class="user-card" data-sly-use.user="com.example.UserModel">
  <!-- Name with placeholder -->
  <h3 data-sly-text="${user.name}">
    Placeholder Name
  </h3>

  <!-- Email -->
  <p class="email" data-sly-text="${user.email}">
    email@placeholder.com
  </p>

  <!-- Role -->
  <span class="badge" data-sly-text="${user.role}">
    Role
  </span>
</div>

In Edit Mode (before the author fills it):

<div class="user-card">
  <h3>Placeholder Name</h3>
  <p class="email">email@placeholder.com</p>
  <span class="badge">Role</span>
</div>

After completion:

<div class="user-card">
  <h3>John Smith</h3>
  <p class="email">john.smith@example.com</p>
  <span class="badge">Administrator</span>
</div>

Example 2: Breadcrumb

<nav aria-label="breadcrumb">
  <ol class="breadcrumb">
    <li class="breadcrumb-item">
      <a href="/" data-sly-text="${'Home'}">Home</a>
    </li>
    <li class="breadcrumb-item">
      <a href="${currentPage.parent.path}"
         data-sly-text="${currentPage.parent.title}">
        Parent Category
      </a>
    </li>
    <li class="breadcrumb-item active"
        data-sly-text="${currentPage.title}">
      Current Page
    </li>
  </ol>
</nav>

Example 3: Product Table

<table class="product-table" data-sly-use.products="com.example.ProductsModel">
  <thead>
    <tr>
      <th>Product</th>
      <th>Price</th>
      <th>Stock</th>
    </tr>
  </thead>
  <tbody data-sly-list.product="${products.items}">
    <tr>
      <!-- Product name -->
      <td data-sly-text="${product.name}">
        Product Name
      </td>

      <!-- Price with formatting -->
      <td data-sly-text="${'$ ' + product.price}">
        $ 0.00
      </td>

      <!-- Stock with conditional color -->
      <td class="${product.stock > 10 ? 'text-success' : 'text-warning'}"
          data-sly-text="${product.stock}">
        0
      </td>
    </tr>
  </tbody>
</table>

Automatic Escaping

Like all HTL expressions, data-sly-text applies automatic HTML escaping:

<!-- Input with HTML -->
${properties.content}  <!-- "<script>alert('xss')</script>" -->

<!-- Escaped output -->
<p data-sly-text="${properties.content}">
  Placeholder
</p>

<!-- Result -->
<p>&lt;script&gt;alert('xss')&lt;/script&gt;</p>

If you want to preserve HTML (from a safe source), use context='html':

<div data-sly-text="${properties.richText @ context='html'}">
  Placeholder
</div>

Context Options

data-sly-text supports all context options:

<!-- Text context - encodes everything -->
<pre data-sly-text="${properties.code @ context='text'}">
  Code placeholder
</pre>

<!-- Number context - only numbers -->
<span data-sly-text="${properties.age @ context='number'}">
  0
</span>

<!-- HTML context - preserves safe HTML -->
<div data-sly-text="${properties.richContent @ context='html'}">
  <p>Placeholder</p>
</div>

Combination with Other Statements

data-sly-text can be combined with other data-sly-*:

With data-sly-test

<!-- Show only if title exists -->
<h2 data-sly-test="${properties.title}"
    data-sly-text="${properties.title}">
  Title Placeholder
</h2>

With data-sly-list

<ul data-sly-list.tag="${properties.tags}">
  <!-- text + list -->
  <li data-sly-text="${tag}">Tag</li>
</ul>

With data-sly-element

<!-- Dynamic tag + content -->
<div data-sly-element="${properties.headingLevel}"
     data-sly-text="${properties.heading}">
  Heading Placeholder
</div>

<!-- If headingLevel = "h2" -->
<h2>My Heading</h2>

When NOT to Use data-sly-text

1. Mixed Content

<!-- ❌ WRONG - overwrites everything! -->
<p data-sly-text="${properties.name}">
  Welcome, <strong>placeholder</strong>!
</p>
<!-- Output: overwrites "Welcome, <strong>" -->

<!-- ✓ CORRECT - use inline expression -->
<p>
  Welcome, <strong data-sly-text="${properties.name}">placeholder</strong>!
</p>

2. Multiple Outputs in the Same Element

<!-- ❌ WRONG -->
<p data-sly-text="${properties.firstName + ' ' + properties.lastName}">
  First Last
</p>

<!-- ✓ CORRECT - more flexible -->
<p>
  <span data-sly-text="${properties.firstName}">First</span>
  <span data-sly-text="${properties.lastName}">Last</span>
</p>

Block Statement Priority

If you use multiple data-sly-* on the same element, the execution order is:

  1. data-sly-use
  2. data-sly-test
  3. data-sly-list / data-sly-repeat
  4. data-sly-text
  5. data-sly-attribute
  6. data-sly-element
  7. data-sly-unwrap
<p data-sly-test="${properties.show}"
   data-sly-text="${properties.content}">
  Placeholder
</p>
<!-- 1. Checks test 2. If true, applies text -->

Best Practices

  1. Use meaningful placeholders: they help authors
  2. Prefer inline ${...} for simple content
  3. Use data-sly-text when:
    • You want visible placeholders
    • The element contains only that output
    • Better compatibility with external tools
  4. Combine with data-sly-test for conditional content
  5. Pay attention to context: specify when necessary

Practical Exercises

  1. Author Profile: Card with name, bio, email using data-sly-text and placeholders
  2. Product List: Table with name, price, availability
  3. Meta Info: Display publication date, author, category with placeholders

Next Lesson

In the next lesson we'll discover data-sly-test for conditional rendering and how to show/hide elements based on conditions.


Lesson #5 of the HTL Tutorial series. ← Previous lesson | Next lesson →