AEM Sightly Style Guide

Sightly is the new HTML templating system for AEM. Our style guide for frontend and backend developers helps to keep your Sightly scripts clean and easy to read.

When Adobe Experience Manager (AEM) 6.0 was introduced, it came with a new HTML templating system called Sightly. Sightly replaces JSP/ESP files and is now the preferred way of processing HTML files in on the server for AEM projects.

Why do we need a style guide?

Sightly is the middle layer where frontend and backend developers come together and work on the same files. It’s important that both sides develop in a common way so that the Sightly scripts remain clean and easy to read. The problems that often arise over time:

  • It’s difficult to read complex Sightly scripts.
  • It’s hard to see what the final HTML markup will be.
  • Extra and unnecessary HTML gets rendered in the final markup.

Often developers write their Sightly code with different priorities in mind. For frontend developers, the HTML must be well structured, semantic and accessible. While for backend developers the data, validation and security are the most important topics. This results in a variety of code styles and ways to write Sightly scripts.

I created this style guide to maintain a consistent code base and avoid confusion between developers. These easy to follow rules will help to make Sightly live up to the meaning of its name.

The name “Sightly” (meaning “pleasing to the eye”) highlights its focus on keeping your markup beautiful, and thus maintainable, once made dynamic.

Sightly style guide

1. HTML

1.1 Always self-close HTML void elements

Although the self-closing "/" is optional in HTML5, not adding it in your Sightly script could result in errors.

<!--/* Bad */-->
<input type="text" name="name">
<img src="smiley.gif" alt="Smiley face" height="42" width="42">
<meta name="author" content="Erik Grijzen">
<link rel="stylesheet" type="text/css" href="styles.css">

<!--/* Good */-->
<input type="text" name="name" />
<img src="smiley.gif" alt="Smiley face" height="42" width="42" />
<meta name="author" content="Erik Grijzen" />
<link rel="stylesheet" type="text/css" href="styles.css" />

2. Comments

2.1 Always use Sightly comments

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

<!-- Never use HTML comments -->

<!--/* Always use Sightly comments */-->

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 display context as possible
<!--/* Bad */-->
<p style="color: ${properties.color @ context='unsafe'};"></p>

<!--/* Good */-->
<p style="color: ${properties.color @ context='styleToken'};"></p>

You can find a list of all available display contexts in the Sightly specification.

4. Block Statements

4.1 Use the "SLY" tag name for all elements that are not part of the 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" data-sly-unwrap></sly>

<!--/* Good */-->
<sly data-sly-resource="${item @ selectors = 'event'}" data-sly-unwrap></sly>

<!--/* Good */-->
<sly data-sly-test="${event.hasDate}" data-sly-unwrap>
...
</sly> 
In AEM version 6.1 elements with the tag name “sly” will get unwrapped automatically, so there 
is no need to include it as an HTML attribute.




<!--/* Bad */-->
<sly data-sly-include="content.html" data-sly-unwrap></sly>

<!--/* Good */-->
<sly data-sly-include="content.html"></sly>
 
4.2 Always wrap component markup inside a data-sly-use statement

The inner Sightly logic will only be executed if the Java or JavaScript logic works without errors.

<!--/* Bad */-->
<sly data-sly-use.teaser="com.example.TeaserComponent" data-sly-unwrap></sly>

<div class="teaser">
<a class="teaser__link" href="${teaser.link}"></a>
</div>

<!--/* Good */-->
<sly data-sly-use.teaser="com.example.TeaserComponent" data-sly-unwrap>
<div class="teaser">
<a class="teaser__link" href="${teaser.link}"></a>
</div>
</sly>
 
4.3 Use meaningful identifier names

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

<!--/* Bad */-->
<sly data-sly-use.comp="com.example.TeaserComponent" data-sly-unwrap>
...
</sly>

<!--/* Good */-->
<sly data-sly-use.teaser="com.example.TeaserComponent" data-sly-unwrap>
...
</sly>
 
4.4 Use camelCase for identifier names

Using camelCase will help to increase the readability of your identifiers.

<!--/* Bad */-->
<sly data-sly-use.mediagallery="com.example.MediaGallery" data-sly-unwrap>
...
</sly>

<!--/* Good */-->
<sly data-sly-use.mediaGallery="com.example.MediaGallery" data-sly-unwrap>
...
</sly>
 
4.5 Always cache test block statement results in an identifier if it repeats itself
<!--/* Bad */-->
<section class="teaser" data-sly-test="${!teaser.empty}">
...
</section>

<div class="cq-placeholder" data-sly-test="${teaser.empty}"></div>

<!--/* Good */-->
<section class="teaser" data-sly-test.hasContent="${!teaser.empty}">
...
</section>

<div class="cq-placeholder" data-sly-test="${!hasContent}"></div>
 
4.6 Always use identifiers instead of the default "item" variable for list block statements
<!--/* Bad */-->
<ul class="tagList" data-sly-list="${tagList.tags}">
<li class="tagList__tag">
<a class="tagList__button" href="${item.url}">${item.title}</a>
</li>
</ul>

<!--/* Good */-->
<ul class="tagList" data-sly-list.tag="${tagList.tags}">
<li class="tagList__tag">
<a class="tagList__button" href="${tag.url}">${tag.title}</a>
</li>
</ul>
 
4.7 Always place block statements after the normal HTML attributes
<!--/* Bad */-->
<p data-sly-test="${teaser.text}" class="teaser__text"></p>

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

<!--/* Good */-->
<section class="teaser" data-sly-test="${!teaser.active}">
…
</section>
 
4.9 Unwrap all includes resources and other HTML elements that are not part of the markup

Elements that are not unwrapped will create unnecessary HTML in the final markup.

<!--/* Bad */-->
<div data-sly-include="content.html"></div>

<!--/* Bad */-->
<div data-sly-test="${teaser.hasImage}">
<div data-sly-resource="${item @ selectors='teaser'}"></div>
</div>

<!--/* Good */-->
<sly data-sly-include="content.html" data-sly-unwrap></sly>

<!--/* Good */-->
<sly data-sly-resource="${item @ selectors='teaser'}" data-sly-test="${teaser.hasImage}" data-sly-unwrap>
...
</sly>
 
4.10 Try to avoid the element, attribute, and text block statements

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

<!--/* Bad */-->
<div data-sly-element="${headlineElement}">${event.year}</div>
<a href="#" data-sly-attribute.href="${event.link}"></a>
<p class="event__year" data-sly-text="${event.year}"></p>

<!--/* Good */-->
<h2>${event.year}</h2>
<a href="${event.link}"></a>
<p class="event__year">${event.year}</p>
 
4.11 Always place unwrap statements at the end of the HTML tag
<!--/* Bad */-->
<sly data-sly-unwrap data-sly-test="${!teaser.active}">
...
</sly>

<!--/* Good */-->
<sly data-sly-test="${!teaser.active}" data-sly-unwrap>
...
</sly>

5. Client Libraries

5.1 Use the resource type (CSS/JS) as the tag name when loading client libraries
<!--/* Bad */--> <head data-sly-use.clientlib="${'/libs/granite/sightly/templates/clientlib.html'}">
<div data-sly-call="${clientLib.css @ categories='project.publish'}" data-sly-unwrap></div>
<div data-sly-call="${clientLib.css @ categories='project.author'}" data-sly-test="${!wcmmode.disabled}"
data-sly-unwrap></div> </head> <body>  ...  <div data-sly-call="${clientLib.js @ categories='project.publish'}"
data-sly-unwrap></div> <div data-sly-call="${clientLib.js @ categories='project.author'}"
data-sly-test="${!wcmmode.disabled}" data-sly-unwrap></div> 
<body>
<!--/* Good */-->
<head data-sly-use.clientlib="${'/libs/granite/sightly/templates/clientlib.html'}">
<css data-sly-call="${clientLib.css @ categories='project.publish'}" data-sly-unwrap></css>
<css data-sly-call="${clientLib.css @ categories='project.author'}" data-sly-test="${!wcmmode.disabled}"
data-sly-unwrap>
</css>
</head>
<body>

 

Contribute

This style guide is also published as an open source project on Github. Do you have new ideas or feedback? Please create a pull request or open an issue if you want to contribute.

Next Blog Post

by Stephan Becker

Content Management,  Developer

Adobe Experience Manager 6 with a MongoDB Setup

With AEM 6 the persistence layer which is used to store content, configurations, and program code, is called a MicroKernel (MK). AEM 6 introduced a new MicroKernel and here's what you should know.

Read more...
Erik Grijzen