{"id":20020666,"url":"https://github.com/netcentric/aem-htl-style-guide","last_synced_at":"2026-03-06T10:31:08.035Z","repository":{"id":35468898,"uuid":"39737135","full_name":"Netcentric/aem-htl-style-guide","owner":"Netcentric","description":"A style guide for the HTML Template Language (HTL), the templating language use by the Adobe Experience Manager (AEM).","archived":false,"fork":false,"pushed_at":"2024-05-30T10:46:32.000Z","size":130,"stargazers_count":138,"open_issues_count":1,"forks_count":48,"subscribers_count":45,"default_branch":"master","last_synced_at":"2025-11-29T08:32:36.701Z","etag":null,"topics":["aem","htl","sightly"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Netcentric.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-07-26T18:41:51.000Z","updated_at":"2025-07-25T16:55:12.000Z","dependencies_parsed_at":"2024-11-13T08:34:29.701Z","dependency_job_id":"c76264b0-7146-4a06-b1a1-0e1928479477","html_url":"https://github.com/Netcentric/aem-htl-style-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Netcentric/aem-htl-style-guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netcentric%2Faem-htl-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netcentric%2Faem-htl-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netcentric%2Faem-htl-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netcentric%2Faem-htl-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Netcentric","download_url":"https://codeload.github.com/Netcentric/aem-htl-style-guide/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Netcentric%2Faem-htl-style-guide/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30171869,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T07:56:45.623Z","status":"ssl_error","status_checked_at":"2026-03-06T07:55:55.621Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aem","htl","sightly"],"created_at":"2024-11-13T08:33:34.359Z","updated_at":"2026-03-06T10:31:07.402Z","avatar_url":"https://github.com/Netcentric.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# AEM HTL Style Guide\nA style guide for the [HTML Template Language](https://docs.adobe.com/docs/en/htl.html) (HTL), formerly known as Sightly, the HTML templating system from Adobe Experience Manager (AEM).\n\n## Table of Contents\n\n  1. [HTML](#html)\n  2. [Comments](#comments)\n  3. [Expression language](#expression-language)\n  4. [Block statements](#block-statements)\n\n\u003ca name='html'\u003e\u003c/a\u003e\n## 1. HTML\n\n  - [1.1](#1.1) \u003ca name='1.1'\u003e\u003c/a\u003e **Avoid inline JavaScript or CSS.**\n  \n    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 `\u003cscript\u003e` or `\u003cstyle\u003e` elements, no block statement can be used within them.\n  \n    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.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csection data-sly-use.teaser=\"com.example.TeaserComponent\" class=\"teaser\"\u003e\n        \u003ch2 class=\"teaser__title\"\u003e${teaser.title}\u003c/h2\u003e\n        \u003cscript\u003e\n            var teaserConfig = {\n                skin: \"${teaser.skin @ context='scriptString'}\",\n                animationSpeed: ${teaser.animationSpeed @ context='number'}\n            };\n        \u003c/script\u003e\n        \u003cstyle\u003e\n            .teaser__title {\n                font-size: ${teaser.titleFontSize @ context='styleToken'}\n            }\n        \u003c/style\u003e\n    \u003c/section\u003e\n    \n    \u003c!--/* Good */--\u003e\n    \u003csection data-sly-use.teaser=\"com.example.TeaserComponent\" data-teaser-config=\"${teaser.jsonConfig}\" class=\"teaser\"\u003e\n        \u003ch2 class=\"teaser__title teaser__title--font-${teaser.titleFontClass}\"\u003e${teaser.title}\u003c/h2\u003e\n    \u003c/section\u003e\n    ```\n\n**[⬆ back to top](#table-of-contents)**\n\n\u003ca name='comments'\u003e\u003c/a\u003e\n## 2. Comments\n\n  - [2.1](#2.1) \u003ca name='2.1'\u003e\u003c/a\u003e **Use HTL comments.**\n  \n    Normal HTML comments get rendered to the final markup. To keep the DOM clean, always use HTL comments over normal HTML comments.\n\n    ```html\n    \u003c!-- Never use HTML comments --\u003e\n \n    \u003c!--/* Always use HTL comments */--\u003e\n    ```\n\n**[⬆ back to top](#table-of-contents)**\n\n\u003ca name='expression-language'\u003e\u003c/a\u003e\n## 3. Expression language\n\n  - [3.1](#3.1) \u003ca name='3.1'\u003e\u003c/a\u003e **Set a display context only if necessary**\n  \n    In most cases you can leave out the display context, because it is determined automatically.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003ca href=\"${teaser.link @ context = 'uri'}\"\u003e\u003c/a\u003e\n \n    \u003c!--/* Good */--\u003e\n    \u003ca href=\"${teaser.link}\"\u003e\u003c/a\u003e\n    ```\n\n  - [3.2](#3.2) \u003ca name='3.2'\u003e\u003c/a\u003e **Use the safest possible display context.**\n\n    From the following list of contexts, always choose the one closest to the top that fits your needs:  \n    `number`: For whole numbers (in HTML, JS or CSS)  \n    `uri`: For links and paths (in HTML, JS or CSS, applied by default for `src` and `href` attributes)  \n    `elementName`: For HTML element names (applied by default by `data-sly-element`)  \n    `attributeName`: For HTML attribute names (applied by default by `data-sly-attribute` for attribute names)  \n    `scriptToken`: For JavaScript identifiers and keywords  \n    `styleToken`: For CSS identifiers and keywords  \n    `scriptString`: For text within JavaScript strings  \n    `styleString`: For text within CSS strings  \n    `attribute`: For HTML attribute values (applied by default for attribute values)  \n    `text`: For HTML text content (applied by default for any content)  \n    `html`: For HTML markup (it filters out all elements and attributes that could be dangerous)  \n    `unsafe`: Unescaped and unfiltered direct output  \n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csection data-sly-use.teaser=\"com.example.TeaserComponent\" class=\"teaser\"\u003e\n        \u003ch4 onclick=\"${teaser.clickHandler @ context='unsafe'}\"\u003e${teaser.title}\u003c/h4\u003e\n        \u003cdiv style=\"color: ${teaser.color @ context='unsafe'};\"\u003e\n            ${teaser.htmlContent @ context='unsafe'}\n        \u003c/div\u003e\n    \u003c/section\u003e\n \n    \u003c!--/* Good */--\u003e\n    \u003csection data-sly-use.teaser=\"com.example.TeaserComponent\" class=\"teaser\"\u003e\n        \u003ch4 onclick=\"${teaser.clickHandler @ context='scriptToken'}\"\u003e${teaser.title}\u003c/h4\u003e\n        \u003cdiv style=\"color: ${teaser.color @ context='styleToken'};\"\u003e\n            ${teaser.htmlContent @ context='html'}\n        \u003c/div\u003e\n    \u003c/section\u003e\n    ```\n\n  - [3.3](#3.3) \u003ca name='3.3'\u003e\u003c/a\u003e **Avoid writing unnecessary expressions for literals.**\n  \n    It might sound obvious, but an expression with just a string literal inside equals just that string literal.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csly data-sly-use.clientlib=\"${'/libs/granite/sightly/templates/clientlib.html'}\"\u003e\n        ...\n    \u003c/sly\u003e\n \n    \u003c!--/* Good */--\u003e\n    \u003csly data-sly-use.clientlib=\"/libs/granite/sightly/templates/clientlib.html\"\u003e\n        ...\n    \u003c/sly\u003e\n    ```\n    \n  - [3.4](#3.4) \u003ca name='3.4'\u003e\u003c/a\u003e **Avoid using the ternary operator unnecessarily.**\n\n    Take advantage of the logical `||` operator to simplify your code. \n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003cdiv class=\"${cssClass ? cssClass : 'my-class'}\"\u003e\u003c/div\u003e\n\n    \u003c!--/* Good */--\u003e\n    \u003cdiv class=\"${cssClass || 'my-class'}\"\u003e\u003c/div\u003e\n    ```\n\n  - [3.5](#3.5) \u003ca name='3.5'\u003e\u003c/a\u003e **Use the native URI manipulation capabilities of HTL.**\n\n    Rolling out a custom URI builder is error prone and hardcoding URL's is even worse. Use [HTL URI Manipulation](https://github.com/adobe/htl-spec/blob/master/SPECIFICATION.md#125-uri-manipulation) instead, in particular, the `extension` option.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003ca href=\"${component.link}.html\"\u003e\u003c/a\u003e\n\n    \u003c!--/* Good */--\u003e\n    \u003ca href=\"${component.link @ extension = 'html'}\"\u003e\u003c/a\u003e\n    ```\n\n  - [3.6](#3.6) \u003ca name='3.6'\u003e\u003c/a\u003e **Drop Method Prefixes When Accessing Properties from Java Getter Functions.**\n\n    When following the [JavaBeans naming conventions](https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/) (as you should) to name your getter methods, you can access the properties with their property name directly. You should access properties this way for consistency and readability.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003cp\u003e${component.getTitle}\u003c/p\u003e\n    \u003ca href=\"${item.link}\" data-sly-unwrap=\"${item.isActive}\"\u003e...\u003c/a\u003e\n\n    \u003c!--/* Good */--\u003e\n    \u003cp\u003e${component.title}\u003c/p\u003e\n    \u003ca href=\"${item.link}\" data-sly-unwrap=\"${item.active}\"\u003e...\u003c/a\u003e\n    ```\n\n**[⬆ back to top](#table-of-contents)**\n\n\u003ca name='block-statements'\u003e\u003c/a\u003e\n## 4. Block statements\n\n  - [4.1](#4.1) \u003ca name='4.1'\u003e\u003c/a\u003e **Use the `sly` tag name for all elements that are not part of the markup.**\n  \n    HTML elements with the tag name `sly` are automatically getting unwrapped and will not be part of the final markup.\n\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003cdiv data-sly-include=\"content.html\" data-sly-unwrap\u003e\u003c/div\u003e\n\n    \u003c!--/* Good */--\u003e\n    \u003csly data-sly-include=\"content.html\"\u003e\u003c/sly\u003e\n    ```\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003cdiv data-sly-resource=\"${item @ selectors='event'}\" data-sly-unwrap\u003e\u003c/div\u003e\n\n    \u003c!--/* Good */--\u003e\n    \u003csly data-sly-resource=\"${item @ selectors = 'event'}\"\u003e\u003c/sly\u003e\n    ```\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003cdiv data-sly-test=\"${event.hasDate}\" data-sly-unwrap\u003e\n        ...\n    \u003c/div\u003e\n\n    \u003c!--/* Good */--\u003e\n    \u003csly data-sly-test=\"${event.hasDate}\"\u003e\n        ...\n    \u003c/sly\u003e\n    ```\n    \n    **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.\n    \n    ```html\n    \u003c!--/* Bad - HTL 1.0 */--\u003e\n    \u003csly data-sly-include=\"content.html\"\u003e\u003c/sly\u003e\n     \n    \u003c!--/* Good - HTL 1.0 */--\u003e\n    \u003csly data-sly-include=\"content.html\" data-sly-unwrap\u003e\u003c/sly\u003e\n    ```\n    \n  - [4.2](#4.2) \u003ca name='4.2'\u003e\u003c/a\u003e **Try to place `data-sly-use` statements only on top-level elements.**\n    \n    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.\n    \n     ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csection class=\"teaser\"\u003e\n        \u003ch3 data-sly-use.teaser=\"com.example.TeaserComponent\"\u003e${teaser.title}\u003c/h3\u003e\n    \u003c/section\u003e\n     \n    \u003c!--/* Good */--\u003e\n    \u003csection data-sly-use.teaser=\"com.example.TeaserComponent\" class=\"teaser\"\u003e\n        \u003ch3\u003e${teaser.title}\u003c/h3\u003e\n    \u003c/section\u003e\n    ```\n    \n  - [4.3](#4.3) \u003ca name='4.3'\u003e\u003c/a\u003e **Use meaningful identifier names.**\n  \n    This will enhance the readability of your HTL scripts and and makes it easier for others to understand.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csly data-sly-use.comp=\"com.example.TeaserComponent\"\u003e\n        ...\n    \u003c/sly\u003e\n     \n    \u003c!--/* Good */--\u003e\n    \u003csly data-sly-use.teaser=\"com.example.TeaserComponent\"\u003e\n        ...\n    \u003c/sly\u003e\n    ```\n    \n  - [4.4](#4.4) \u003ca name='4.4'\u003e\u003c/a\u003e **Use lowerCamelCase for identifier names.**\n\n    Using lowerCamelCase (You start by making the first word lowercase. Then, you capitalize the first letter of each word that follows i.e.: \"sampleIdentifierName\") will help to increase the readability of your identifiers. Notice though that\n    HTL will internally only use (and log) full lowercase identifiers. Also dashes are not allowed for identifiers.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csly data-sly-use.mediagallery=\"com.example.MediaGallery\"\u003e\n        ...\n    \u003c/sly\u003e\n\n    \u003c!--/* Good */--\u003e\n    \u003csly data-sly-use.mediaGallery=\"com.example.MediaGallery\"\u003e\n        ...\n    \u003c/sly\u003e\n    ```\n\n  - [4.5](#4.5) \u003ca name='4.5'\u003e\u003c/a\u003e **Re-use expressions with identifiers**\n\n    If a test block statement is used multiple times, define an identifer and re-use it this way instead. This will allow the htl compiler to cache the expression result and will also make your code easier to read and understand.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csection data-sly-test=\"${!teaser.empty}\" class=\"teaser\"\u003e\n        ...\n    \u003c/section\u003e\n     \n    \u003cdiv data-sly-test=\"${teaser.empty}\" class=\"cq-placeholder\"\u003e\u003c/div\u003e\n     \n    \u003c!--/* Good */--\u003e\n    \u003csection data-sly-test.hasContent=\"${!teaser.empty}\" class=\"teaser\"\u003e\n        ...\n    \u003c/section\u003e\n     \n    \u003cdiv data-sly-test=\"${!hasContent}\" class=\"cq-placeholder\"\u003e\u003c/div\u003e\n    ```\n\n    Similarly, if a generic expression is used multiple times, define an identifer with `data-sly-set` and re-use it, for the same reasons stated above.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003cdiv data-sly-unwrap=\"${!(wcmmode.edit || wcmmode.preview) || resource.hasChildren}\"\u003e\n        \u003csly\n            data-sly-test=\"${resource.hasChildren}\"\n            ...\u003e\n        \u003c/sly\u003e\n        \u003csly\n            data-sly-test=\"${(wcmmode.edit || wcmmode.preview) \u0026\u0026 !resource.hasChildren}\"\n            .... \u003e\n        \u003c/sly\u003e\n    \u003c/div\u003e\n     \n    \u003c!--/* Good */--\u003e\n    \u003cdiv\n         data-sly-set.editMode=\"${(wcmmode.edit || wcmmode.preview)}\"\n         data-sly-set.hasChildren=\"${resource.hasChildren}\"\n         data-sly-unwrap=\"${!editMode || hasChildren}\"\u003e\n        \u003csly\n            data-sly-test=\"${hasChildren}\"\n            ...\u003e\n        \u003c/sly\u003e\n        \u003csly\n            data-sly-test=\"${editMode \u0026\u0026 !hasChildren}\"\n            ...\u003e\n        \u003c/sly\u003e\n    \u003c/div\u003e\n    ```\n\n  - [4.6](#4.6) \u003ca name='4.6'\u003e\u003c/a\u003e **Use identifiers instead of the default “item” variable for list block statements.**\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003cul data-sly-list=\"${tagList.tags}\" class=\"tagList\"\u003e\n        \u003cli class=\"tagList__tag\"\u003e\n            \u003ca class=\"tagList__button\" href=\"${item.url}\"\u003e${item.title}\u003c/a\u003e\n        \u003c/li\u003e\n    \u003c/ul\u003e\n     \n    \u003c!--/* Good */--\u003e\n    \u003cul data-sly-list.tag=\"${tagList.tags}\" class=\"tagList\"\u003e\n        \u003cli class=\"tagList__tag\"\u003e\n            \u003ca class=\"tagList__button\" href=\"${tag.url}\"\u003e${tag.title}\u003c/a\u003e\n        \u003c/li\u003e\n    \u003c/ul\u003e\n    ```\n    \n  - [4.7](#4.7) \u003ca name='4.7'\u003e\u003c/a\u003e **Place block statements before the regular HTML attributes.**\n\n    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](https://github.com/Netcentric/aem-htl-style-guide/issues/25).\n    \n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003cp class=\"teaser__text\" data-sly-test=\"${teaser.text}\"\u003e\u003c/p\u003e\n         \n    \u003c!--/* Good */--\u003e\n    \u003cp data-sly-test=\"${teaser.text}\" class=\"teaser__text\"\u003e\u003c/p\u003e\n    ```\n \n    \n  - [4.8](#4.8) \u003ca name='4.8'\u003e\u003c/a\u003e **Use existing HTML elements for your block statements if possible.**\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csly data-sly-test=\"${!teaser.active}\"\u003e\n        \u003csection class=\"teaser\"\u003e\n            …\n        \u003c/section\u003e\n    \u003c/sly\u003e\n     \n    \u003c!--/* Good */--\u003e\n    \u003csection data-sly-test=\"${!teaser.active}\" class=\"teaser\"\u003e\n        …\n    \u003c/section\u003e\n    ```\n    \n  - [4.9](#4.9) \u003ca name='4.9'\u003e\u003c/a\u003e **Avoid the `element`, `attribute` and `text` block statements.**\n  \n    It's a lot cleaner and explicit to write your HTL scripts without these block statements.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003cdiv data-sly-element=\"${headlineElement}\"\u003e${event.year}\u003c/div\u003e\n    \u003ca data-sly-attribute.href=\"${event.link}\" href=\"#\"\u003e\u003c/a\u003e\n    \u003cp data-sly-text=\"${event.year}\" class=\"event__year\"\u003e\u003c/p\u003e\n     \n    \u003c!--/* Good */--\u003e\n    \u003ch2\u003e${event.year}\u003c/h2\u003e\n    \u003ca href=\"${event.link}\"\u003e\u003c/a\u003e\n    \u003cp class=\"event__year\"\u003e${event.year}\u003c/p\u003e\n    ```\n    \n  - [4.10](#4.10) \u003ca name='4.10'\u003e\u003c/a\u003e **Define your templates in a separate file.**\n\n    It's cleaner to create separate files for your template markup, so your HTL scripts will not get cluttered.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csly data-sly-use.teaser=\"com.example.TeaserComponent\"\u003e\n      \u003csly data-sly-template.teaserSmall=\"${@ title, text}\"\u003e\n        \u003ch2\u003e${title}\u003c/h2\u003e\n        \u003cp\u003e${text}\u003c/p\u003e\n      \u003c/sly\u003e\n      \n      \u003csly data-sly-call=\"${teaserSmall @ title=teaser.title, text=teaser.text}\"\u003e\u003c/sly\u003e\n    \u003c/sly\u003e\n    \n    \u003c!--/* Good - Separate template file: \"teaser-templates.html\" */--\u003e\n    \u003csly data-sly-template.teaserSmall=\"${@ teaserModel}\"\u003e\n      \u003ch2\u003e${teaserModel.title}\u003c/h2\u003e\n      \u003cp\u003e${teaserModel.text}\u003c/p\u003e\n    \u003c/sly\u003e\n    \n    \u003c!--/* Good - HTL script */--\u003e\n    \u003csly data-sly-use.teaser=\"com.example.TeaserComponent\" data-sly-use.teaserTemplates=\"teaser-templates.html\"\u003e\n      \u003csly data-sly-call=\"${teaserTemplates.teaserSmall @ teaserModel=teaser}\"\u003e\u003c/sly\u003e\n    \u003c/sly\u003e\n    ```\n\n  - [4.11](#4.11) \u003ca name='4.11'\u003e\u003c/a\u003e **Avoid using data-sly-test to set arbitrary variable bindings**\n\n    Instead of binding a variable with `data-sly-test`, use the purposefully defined `data-sly-set`. This avoids unintentionally hiding elements if the result of the expression evaluates to false (see [HTL expressions evaluating to false](https://github.com/adobe/htl-spec/blob/master/SPECIFICATION.md#1151-boolean) ) and/or stopping the evaluation of further block statements; This is specially difficult to debug when various `data-sly-test` statements affect the same element.\n\n    ```html\n    \u003c!--/* Instead of */--\u003e\n    \u003csly data-sly-test=\"${person.firstName \u0026\u0026 person.lastName \u0026\u0026 person.image}\" data-sly-test.fullName=\"${person.firstName} ${person.lastName}\"\u003e\n    \u003ch1\u003e${fullName}\u003c/h1\u003e\n    \u003cimg src=${person.image}\" alt=\"${fullName}\"/\u003e\n\n    \u003c!--/* Use */--\u003e\n    \u003csly data-sly-test=\"${person.firstName \u0026\u0026 person.lastName \u0026\u0026 person.image}\" data-sly-set.fullName=\"${person.firstName} ${person.lastName}\"\u003e\n    \u003ch1\u003e${fullName}\u003c/h1\u003e\n    \u003cimg src=${person.image}\" alt=\"${fullName}\"/\u003e\n    ```\n\n  - [4.12](#4.12) \u003ca name='4.12'\u003e\u003c/a\u003e **Avoid unnecessary `\u003csly\u003e` tags.**\n\n    It's cleaner and easier to understand your intentions if you add your block statements in the relevant elements directly instead of wrapping them with an `sly` tag.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csly data-sly-test.title=\"${component.title}\"\u003e\n      \u003ch1\u003e${title}\u003c/h1\u003e\n    \u003c/sly\u003e\n\n    \u003c!--/* Good */--\u003e\n    \u003ch1 data-sly-test.title=\"${component.title}\"\u003e${title}\u003c/h1\u003e\n    ```\n\n  - [4.13](#4.13) \u003ca name='4.13'\u003e\u003c/a\u003e **Use an explicit `\u003c/sly\u003e` end tag to close `\u003csly\u003e` tags.**\n\n    Because `sly` is neither a void nor a foreign element (See [html5 start tags](https://html.spec.whatwg.org/multipage/syntax.html#start-tags)), it must be explicitly closed with an end tag `\u003c/sly\u003e`. Using a self-closing tag is **not** allowed.\n\n    ```html\n    \u003c!--/* Bad */--\u003e\n    \u003csly data-sly-include=\"content.html\"/\u003e\n\n    \u003c!--/* Good */--\u003e\n    \u003csly data-sly-include=\"content.html\"\u003e\u003c/sly\u003e\n    ```\n\n**[⬆ back to top](#table-of-contents)**\n\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 Netcentric\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n**[⬆ back to top](#table-of-contents)**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetcentric%2Faem-htl-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetcentric%2Faem-htl-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetcentric%2Faem-htl-style-guide/lists"}