• Stars
    star
    138
  • Rank 264,508 (Top 6 %)
  • Language
  • License
    MIT License
  • Created over 9 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A style guide for the HTML Template Language (HTL), the templating language use by the Adobe Experience Manager (AEM).

AEM HTL Style Guide

A style guide for the HTML Template Language (HTL), formerly known as Sightly, the HTML templating system from Adobe Experience Manager (AEM).

Table of Contents

  1. HTML
  2. Comments
  3. Expression language
  4. Block statements

1. HTML

  • 1.1 Avoid inline JavaScript or CSS.

    In order to encourage keeping a clean separation of concerns, HTL has by design some limitations for inline JavaScript or CSS. First, because HTL doesn't parse JavaScript or CSS, and therefore cannot automatically define the corresponding escaping, all expressions written there must provide an explicit context option. Then, because the HTML grammar ignores elements located inside a <script> or <style> elements, no block statement can be used within them.

    Therefore JavaScript and CSS code should instead be placed into corresponding .js and .css files. Data attributes are the easiest way to communicate values to JavaScript, and class names are the best way to trigger specific styles.

    <!--/* Bad */-->
    <section data-sly-use.teaser="com.example.TeaserComponent" class="teaser">
        <h2 class="teaser__title">${teaser.title}</h2>
        <script>
            var teaserConfig = {
                skin: "${teaser.skin @ context='scriptString'}",
                animationSpeed: ${teaser.animationSpeed @ context='number'}
            };
        </script>
        <style>
            .teaser__title {
                font-size: ${teaser.titleFontSize @ context='styleToken'}
            }
        </style>
    </section>
    
    <!--/* Good */-->
    <section data-sly-use.teaser="com.example.TeaserComponent" data-teaser-config="${teaser.jsonConfig}" class="teaser">
        <h2 class="teaser__title teaser__title--font-${teaser.titleFontClass}">${teaser.title}</h2>
    </section>

⬆ back to top

2. Comments

  • 2.1 Always use HTL comments.

    Normal HTML comments get rendered to the final markup. To keep the DOM clean, always use HTL comments over normal HTML comments.

    <!-- Never use HTML comments -->
    
    <!--/* Always use HTL comments */-->

⬆ back to top

3. Expression language

  • 3.1 Only set a display context if necessary

    In most cases you can leave out the display context, because it is determined automatically.

    <!--/* Bad */-->
    <a href="${teaser.link @ context = 'uri'}"></a>
    
    <!--/* Good */-->
    <a href="${teaser.link}"></a>
  • 3.2 Always use the safest possible display context.

    From the following list of contexts, always choose the one closest to the top that fits your needs:
    number: For whole numbers (in HTML, JS or CSS)
    uri: For links and paths (in HTML, JS or CSS, applied by default for src and href attributes)
    elementName: For HTML element names (applied by default by data-sly-element)
    attributeName: For HTML attribute names (applied by default by data-sly-attribute for attribute names)
    scriptToken: For JavaScript identifiers and keywords
    styleToken: For CSS identifiers and keywords
    scriptString: For text within JavaScript strings
    styleString: For text within CSS strings
    attribute: For HTML attribute values (applied by default for attribute values)
    text: For HTML text content (applied by default for any content)
    html: For HTML markup (it filters out all elements and attributes that could be dangerous)
    unsafe: Unescaped and unfiltered direct output

    <!--/* Bad */-->
    <section data-sly-use.teaser="com.example.TeaserComponent" class="teaser">
        <h4 onclick="${teaser.clickHandler @ context='unsafe'}">${teaser.title}</h4>
        <div style="color: ${teaser.color @ context='unsafe'};">
            ${teaser.htmlContent @ context='unsafe'}
        </div>
    </section>
    
    <!--/* Good */-->
    <section data-sly-use.teaser="com.example.TeaserComponent" class="teaser">
        <h4 onclick="${teaser.clickHandler @ context='scriptToken'}">${teaser.title}</h4>
        <div style="color: ${teaser.color @ context='styleToken'};">
            ${teaser.htmlContent @ context='html'}
        </div>
    </section>
  • 3.3 Don't write unnecessary expressions for literals.

    It might sound obvious, but an expression with just a string literal inside equals just that string literal.

    <!--/* Bad */-->
    <sly data-sly-use.clientlib="${'/libs/granite/sightly/templates/clientlib.html'}">
        ...
    </sly>
    
    <!--/* Good */-->
    <sly data-sly-use.clientlib="/libs/granite/sightly/templates/clientlib.html">
        ...
    </sly>

⬆ back to top

4. Block statements

  • 4.1 Use the SLY tag name for all elements that are not part of the markup.

    HTML elements with the tag name SLY are automatically getting unwrapped and will not be part of the final markup.

    <!--/* Bad */-->
    <div data-sly-include="content.html" data-sly-unwrap></div>
     
    <!--/* Bad */-->
    <div data-sly-resource="${item @ selectors='event'}" data-sly-unwrap></div>
     
    <!--/* Bad */-->
    <div data-sly-test="${event.hasDate}" data-sly-unwrap>
        ...
    </div>
     
    <!--/* Good */-->
    <sly data-sly-include="content.html"></sly>
     
    <!--/* Good */-->
    <sly data-sly-resource="${item @ selectors = 'event'}"></sly>
     
    <!--/* Good */-->
    <sly data-sly-test="${event.hasDate}">
        ...
    </sly>

    IMPORTANT - The SLY element will not automatically unwrap itself if you use HTL 1.0 (AEM 6.0). In that case, you still have to add the "data-sly-unwrap" attribute.

    <!--/* Bad - HTL 1.0 */-->
    <sly data-sly-include="content.html"></sly>
     
    <!--/* Good - HTL 1.0 */-->
    <sly data-sly-include="content.html" data-sly-unwrap></sly>
  • 4.2 Try to place use data-sly-use statements only on top-level elements.

    Since data-sly-use identifiers are always global (https://docs.adobe.com/docs/en/htl/docs/use-api/java.html#Local%20identifier), these attributes should only be placed in the top-level element. That way one can easily see name clashes and also it prevents initializing the same object twice.

    <!--/* Bad */-->
    <section class="teaser">
       <h3 data-sly-use.teaser="com.example.TeaserComponent">${teaser.title}</h3>
    </section>
    
    <!--/* Good */-->
    <section data-sly-use.teaser="com.example.TeaserComponent" class="teaser">
       <h3>${teaser.title}</h3>
    </section>
  • 4.3 Use meaningful identifier names.

    This will enhance the readability of your HTL scripts and and makes it easier for others to understand.

    <!--/* Bad */-->
    <sly data-sly-use.comp="com.example.TeaserComponent">
        ...
    </sly>
     
    <!--/* Good */-->
    <sly data-sly-use.teaser="com.example.TeaserComponent">
        ...
    </sly>
  • 4.4 Use camelcase for identifier names.

    Using camelCase will help to increase the readability of your identifiers. Notice though that HTL will internally only use (and log) lowercase identifiers. Also dashes are not allowed for identifiers.

    <!--/* Bad */-->
    <sly data-sly-use.mediagallery="com.example.MediaGallery">
        ...
    </sly>
     
    <!--/* Good */-->
    <sly data-sly-use.mediaGallery="com.example.MediaGallery">
        ...
    </sly>
  • 4.5 Always cache test block statement results in an identifier if it repeats itself.

    <!--/* Bad */-->
    <section data-sly-test="${!teaser.empty}" class="teaser">
        ...
    </section>
     
    <div data-sly-test="${teaser.empty}" class="cq-placeholder"></div>
     
    <!--/* Good */-->
    <section data-sly-test.hasContent="${!teaser.empty}" class="teaser">
        ...
    </section>
     
    <div data-sly-test="${!hasContent}" class="cq-placeholder"></div>
  • 4.6 Always use identifiers instead of the default β€œitem” variable for list block statements.

    <!--/* Bad */-->
    <ul data-sly-list="${tagList.tags}" class="tagList">
        <li class="tagList__tag">
            <a class="tagList__button" href="${item.url}">${item.title}</a>
        </li>
    </ul>
     
    <!--/* Good */-->
    <ul data-sly-list.tag="${tagList.tags}" class="tagList">
        <li class="tagList__tag">
            <a class="tagList__button" href="${tag.url}">${tag.title}</a>
        </li>
    </ul>
  • 4.7 Always place block statements before the regular HTML attributes.

    The reason for that is that regular HTML attributes might use HTL variables which have been declared in the same element via data-sly-use. One should always declare things before using them. Also HTL block elements might influence if the element appears at all (via data-sly-test) or multiple times (via data-sly-repeat) and therefore are just too important to put them at the end of the attribute list. Further details in issue 25.

    <!--/* Bad */-->
    <p class="teaser__text" data-sly-test="${teaser.text}"></p>
         
    <!--/* Good */-->
    <p data-sly-test="${teaser.text}" class="teaser__text"></p>
  • 4.8 Always use existing HTML elements for your block statements if possible.

    <!--/* Bad */-->
    <sly data-sly-test="${!teaser.active}">
        <section class="teaser">
            …
        </section>
    </sly>
     
    <!--/* Good */-->
    <section data-sly-test="${!teaser.active}" class="teaser">
        …
    </section>
  • 4.9 Try to avoid the element, attribute and text block statements.

    It's a lot cleaner and explicit writing your HTL scripts without these block statements.

    <!--/* Bad */-->
    <div data-sly-element="${headlineElement}">${event.year}</div>
    <a data-sly-attribute.href="${event.link}" href="#"></a>
    <p data-sly-text="${event.year}" class="event__year"></p>
     
    <!--/* Good */-->
    <h2>${event.year}</h2>
    <a href="${event.link}"></a>
    <p class="event__year">${event.year}</p>
  • 4.10 Always define your templates in a separate file.

    It's cleaner to create separate files for your template markup, so your HTL scripts will not get cluttered.

    <!--/* Bad */-->
    <sly data-sly-use.teaser="com.example.TeaserComponent">
      <sly data-sly-template.teaserSmall="${@ title, text}">
        <h2>${title}</h2>
        <p>${text}</p>
      </sly>
      
      <sly data-sly-call="${teaserSmall @ title=teaser.title, text=teaser.text}"></sly>
    </sly>
    
    <!--/* Good - Separate template file: "teaser-templates.html" */-->
    <sly data-sly-template.teaserSmall="${@ teaserModel}">
      <h2>${teaserModel.title}</h2>
      <p>${teaserModel.text}</p>
    </sly>
    
    <!--/* Good - HTL script */-->
    <sly data-sly-use.teaser="com.example.TeaserComponent" data-sly-use.teaserTemplates="teaser-templates.html">
      <sly data-sly-call="${teaserTemplates.teaserSmall @ teaserModel=teaser}"></sly>
    </sly>

⬆ back to top

License

The MIT License (MIT)

Copyright (c) 2015 Netcentric

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

⬆ back to top

More Repositories

1

accesscontroltool

Rights and roles management for AEM made easy
Java
150
star
2

fe-build

All-in-one solution for modern Frontend projects, with special focus on AEM (Adobe Experience Manager)
JavaScript
20
star
3

vault-upgrade-hook

Jackrabbit FileVault Install Hook to perform additional actions during package installation
Java
19
star
4

progux

Progressive User Experience Library
JavaScript
17
star
5

pickaxe-security-scanner

Pickaxe is a fast and customizable security scan library which simplifies security testing for web applications like Adobe Experience Manager or API services. It can be plugged into a maven build to execute build-in checks or custom user provided security checks. Custom security checks can be defined via YAML files or a groovy based DSL.
Groovy
13
star
6

aemmjml

mjml for Adobe Experience Manager
Java
9
star
7

system-env-install-hook

Elastic AEM instances made easy.
Java
7
star
8

healthcheck-migration-kit

Allows to migrate an AEM 6.4/6.5 instance to Felix Health Checks
Shell
5
star
9

web-performance-challenge

Website with web performance and accessibility bad practices
CSS
4
star
10

cloudformation-iac

CloudFormation framework for AWS based project infrastructure
4
star
11

stylelint-config

Cognizant Netcentric's coding and style rules for Stylelint
JavaScript
4
star
12

aem-cloud-validator

Jackrabbit FileVault validator which verifies that a package complies with the AEM as a Cloud Service deployment restrictions outlined at https://experienceleague.adobe.com/docs/experience-manager-learn/cloud-service/debugging/debugging-aem-as-a-cloud-service/build-and-deployment.html
Java
4
star
13

aem-nodetypes

Provides a CND file with all Node Types and Namespaces defined in AEM
3
star
14

access-control-validator

Java
3
star
15

aem-taggable-image

Taggable Image Component for Adobe Experience Manager
Java
3
star
16

aem-classification

Jackrabbit FileVault Validator and classification maps for AEM Content Classification
Java
3
star
17

cn-website

JavaScript
2
star
18

eddys-collection

JavaScript
2
star
19

apply-server

Deploy to servers/run scripts on servers via http
Java
2
star
20

aem-replication-metadata-validator

Jackrabbit FileVault validator ensuring valid replication metadata in certain nodes of content packages
Java
2
star
21

adaptto2016-jenkins-pipeline-demo

A short demo repository of how to create a Jenkins Pipeline for a Sling project using Docker images for build and test.
Shell
2
star
22

adaptto2016-slingshot

Copy of the Sling Sample Application Slingshot to be used in our Jenkins Pipeline Demo. To reduce disk size and time for an initial clone by Jenkins, this has been created as thin copy rather than a fork.
Java
1
star
23

progux-demo-site

Documentation/marketing website for ProgUX Library
Nunjucks
1
star
24

maven-ext-repos-from-env

Allows to auto-configure maven repositories from system environment
Java
1
star
25

envelop

JavaScript
1
star
26

component-loader

JavaScript
1
star