HTL Tutorial #10: data-sly-attribute - Manipulating HTML Attributes
HTL Tutorial #10: data-sly-attribute - Manipulating HTML Attributes
What is data-sly-attribute?
data-sly-attribute allows you to dynamically manipulate HTML attributes: add, modify, or remove attributes based on conditions or data.
Basic Syntax
Single Attribute
<div data-sly-attribute.attributeName="${value}">
Content
</div>Multiple Attributes
<div data-sly-attribute="${object}">
Content
</div>Simple Examples
Adding an Attribute
<!-- Adds data-id dynamically -->
<div data-sly-attribute.data-id="${product.id}">
${product.name}
</div>Output:
<div data-id="12345">
Laptop
</div>Modifying Existing Attribute
<!-- Override class attribute -->
<div class="card" data-sly-attribute.class="${'card ' + product.status}">
Content
</div>Output (if product.status = 'active'):
<div class="card active">
Content
</div>Removing an Attribute
If the value is null, false, or an empty string, the attribute is removed:
<div title="Default title"
data-sly-attribute.title="${properties.customTitle}">
Hover me
</div>If properties.customTitle is null:
<div>
Hover me
</div>If properties.customTitle = 'Custom':
<div title="Custom">
Hover me
</div>Multiple Attributes with Object
You can pass an object to set multiple attributes at once:
<div data-sly-use.attrs="com.example.AttributesModel"
data-sly-attribute="${attrs.htmlAttributes}">
Content
</div>Java Model:
@Model(adaptables = Resource.class)
public class AttributesModel {
public Map<String, String> getHtmlAttributes() {
Map<String, String> attrs = new HashMap<>();
attrs.put("data-id", "123");
attrs.put("data-type", "product");
attrs.put("role", "article");
return attrs;
}
}Output:
<div data-id="123" data-type="product" role="article">
Content
</div>Common Patterns
1. Conditional CSS Classes
<div class="card"
data-sly-attribute.class="${'card ' +
(product.featured ? 'featured ' : '') +
(product.onSale ? 'on-sale' : '')}">
${product.name}
</div>Output (featured=true, onSale=false):
<div class="card featured">
Laptop
</div>2. Dynamic Data Attributes
<div data-sly-use.product="com.example.ProductModel"
data-sly-attribute.data-product-id="${product.id}"
data-sly-attribute.data-price="${product.price}"
data-sly-attribute.data-category="${product.category}">
${product.name}
</div>Output:
<div data-product-id="123" data-price="99.99" data-category="electronics">
Laptop
</div>3. ARIA Attributes for Accessibility
<button data-sly-attribute.aria-expanded="${menu.isOpen}"
data-sly-attribute.aria-controls="${menu.panelId}">
Menu
</button>
<div data-sly-attribute.id="${menu.panelId}"
data-sly-attribute.aria-hidden="${!menu.isOpen}">
<!-- Menu content -->
</div>4. Link with Conditional Target
<a href="${link.url}"
data-sly-attribute.target="${link.external ? '_blank' : ''}"
data-sly-attribute.rel="${link.external ? 'noopener noreferrer' : ''}">
${link.title}
</a>Output (external link):
<a href="https://example.com" target="_blank" rel="noopener noreferrer">
Visit example
</a>Output (internal link - attributes removed):
<a href="/about">
About us
</a>Combining with Other Statements
With data-sly-test
<div data-sly-test="${properties.customId}"
data-sly-attribute.id="${properties.customId}">
<!-- Only if customId exists, the attribute is added -->
</div>With data-sly-list
<ul data-sly-list.item="${properties.items}">
<li data-sly-attribute.class="${itemList.first ? 'first' : ''}
${itemList.last ? 'last' : ''}">
${item}
</li>
</ul>HTML5 Boolean Attributes
For HTML5 boolean attributes like disabled, checked, readonly:
<!-- ✓ CORRECT - use true/false -->
<input type="checkbox"
data-sly-attribute.checked="${user.subscribed}">
<!-- If user.subscribed = true -->
<input type="checkbox" checked>
<!-- If user.subscribed = false -->
<input type="checkbox"><button data-sly-attribute.disabled="${!product.available}">
Buy
</button>
<!-- If available = false -->
<button disabled>Buy</button>
<!-- If available = true -->
<button>Buy</button>Complete Example: Image Component
<div data-sly-use.image="com.example.ImageModel" class="image-wrapper">
<img src="${image.src}"
data-sly-attribute.alt="${image.alt}"
data-sly-attribute.title="${image.title}"
data-sly-attribute.width="${image.width}"
data-sly-attribute.height="${image.height}"
data-sly-attribute.loading="${imageList.first ? '' : 'lazy'}"
data-sly-attribute.class="${'responsive-image ' + (image.rounded ? 'rounded' : '')}"
data-sly-attribute.data-caption="${image.caption}">
<!-- Caption only if present -->
<p data-sly-test="${image.caption}" class="caption">
${image.caption}
</p>
</div>Output (with all data):
<div class="image-wrapper">
<img src="/content/dam/image.jpg"
alt="Image description"
title="Image title"
width="800"
height="600"
loading="lazy"
class="responsive-image rounded"
data-caption="Photo taken in 2025">
<p class="caption">Photo taken in 2025</p>
</div>Complete Example: Form Input
<div data-sly-use.field="com.example.FormFieldModel">
<input type="${field.type}"
name="${field.name}"
data-sly-attribute.id="${field.id}"
data-sly-attribute.value="${field.value}"
data-sly-attribute.placeholder="${field.placeholder}"
data-sly-attribute.required="${field.required}"
data-sly-attribute.disabled="${field.disabled}"
data-sly-attribute.minlength="${field.minLength}"
data-sly-attribute.maxlength="${field.maxLength}"
data-sly-attribute.pattern="${field.pattern}"
data-sly-attribute.aria-label="${field.label}"
data-sly-attribute.aria-describedby="${field.hasError ? field.errorId : ''}"
data-sly-attribute.class="${'form-control ' + (field.hasError ? 'is-invalid' : '')}">
<!-- Error message -->
<div data-sly-test="${field.hasError}"
data-sly-attribute.id="${field.errorId}"
class="invalid-feedback">
${field.errorMessage}
</div>
</div>Special Attributes
href and src - URI Context
HTL automatically applies context='uri' to href and src:
<a href="${link.url}">Link</a>
<!-- Automatically protected against javascript:, data:, etc -->
<!-- Equivalent to: -->
<a data-sly-attribute.href="${link.url @ context='uri'}">Link</a>style Attribute
<div data-sly-attribute.style="${'background-color: ' + theme.bgColor +
'; color: ' + theme.textColor}">
Styled content
</div>Warning: Prefer CSS classes when possible!
Best Practices
- Remove empty attributes: HTL does this automatically with
null/false/"" - Automatic context: No need to specify
@ context='uri'for href/src - Boolean attributes: Use
true/falsedirectly - CSS classes: Prefer CSS classes over inline styles
- ARIA attributes: Use for accessibility
- Data attributes: Perfect for JavaScript hooks
- Objects for multiple attributes: Cleaner when you have many attributes
Attribute Priority
If an attribute is defined both in HTML and with data-sly-attribute, data-sly-attribute wins:
<div class="original"
data-sly-attribute.class="${'new-class'}">
Content
</div>
<!-- Output: -->
<div class="new-class">
Content
</div>To preserve and add:
<div class="original"
data-sly-attribute.class="${'original ' + additionalClass}">
Content
</div>Common Mistakes
❌ Incorrect attribute name
<!-- WRONG - use data-sly-attribute.name -->
<div data-sly-attribute="data-id"="${value}">
<!-- CORRECT -->
<div data-sly-attribute.data-id="${value}">❌ Forgetting the dot
<!-- WRONG - missing the . -->
<div data-sly-attributeclass="${value}">
<!-- CORRECT -->
<div data-sly-attribute.class="${value}">❌ Boolean attributes with strings
<!-- WRONG - use true/false -->
<input data-sly-attribute.disabled="${'disabled'}">
<!-- CORRECT -->
<input data-sly-attribute.disabled="${true}">Practical Exercises
- Card Component: Create cards with dynamic attributes (id, data-*, class)
- Link List: List of links with target="_blank" only for external ones
- Form Builder: Form with validation and ARIA attributes
- Image Gallery: Gallery with lazy loading and dimensional attributes
Next Lesson
In the next lesson we'll explore data-sly-element to dynamically change the HTML tag of an element.
Lesson #10 of the HTL Tutorial series. ← Previous lesson | Next lesson →