Web Templates Style Guide and Coding Conventions

This document shares best practices that Marketing Cloud Personalization template developers follow for writing consistent HTML (Handlebars), CSS, and JavaScript code. Use this documentation as a guide for developing your own templates.

Handlebars HTML 

HTML Syntax 

  • Indent nested elements 4 spaces (one press of the TAB key in the template editor).

  • Break long lines to improve readability, up to 120 characters maximum per line. Place HTML attributes that extend beyond 120 characters on a new continuation line, indented 4 spaces.

  • Use double quotes ( "" ) instead of single quotes ( '' ) for HTML attributes, as shown in the following example.

    1<a class="evg-cta evg-btn evg-btn-primary evg-btn-lg" href="/sale"></a>
  • Contain all the handlebars HTML content within a single element.

  • Write all code in lowercase, including HTML element names, attributes, and attribute values.

  • Use HTML elements for their designed purpose. Whenever possible, use semantic elements that describe the meaning of the content. See the section on “Accessibility” for more details.

ID and Class Nomenclature 

  • Add an ID attribute to the outermost element, using a name specific to the template being built, and prefix with the evg- namespace (for example, id=“evg-hero-banner”). Use an ID for only this outermost HTML element and do not use the same ID in more than one template.
  • Use classes for all other nested elements. Prefix classes with the evg- namespace (for example, class=“evg-btn”).
  • Use hyphens to separate words in class and id names.
1<div id="evg-sale-banner">
2  <h1 class="evg-header evg-h1">One Day Sale!</h1>
3  <a class="evg-cta evg-btn evg-btn-primary" href="/sale">SHOP</a>
4</div>

Template HTML Classes 

For suggested evg- prefixed class names and descriptions of their intended purpose, as well as examples of CSS styling, refer to Template HTML Classes and CSS.

Attributes Order 

List your HTML attributes in the following order to improve readability.

  1. class
  2. id, name
  3. data-*, data-evg-*
  4. src, for, type, href, value
  5. title, alt
  6. role, aria-*
  7. style

Campaign Stats Tracking 

If you would like to track campaign stats with Personalization, use the data attributes (data-evg-*) available in the Handlebars HTML. These data attributes require that the Campaign Stat Tracking gear is installed and enabled for your dataset.

Example:

1<div
2  id="evg-new-template"
3  data-evg-campaign-id="{{campaign}}"
4  data-evg-experience-id="{{experience}}"
5  data-evg-user-group="{{userGroup}}"
6>
7  ...
8</div>

See the Campaign Stats article on this site to learn more.

Comments 

For comments you wish to keep in the Handlebars-generated HTML output, use the native HTML comment format:

1<!-- This comment will show up as a HTML comment -->
2
3<!--
4    This comment will also
5    show up as a HTML comment
6-->

For comments you wish to remove in the resulting HTML output, use the following Handlebars HTML comment format.

1{{! Single-line comments go here. This comment will not appear in the HTML output}}
2
3{{!
4    Multi-line comments go here.
5    This comment will not appear in the HTML output.
6}}

Any Handlebars HTML comment that includes double curly braces or Handlebars expressions must adhere to the following format. These comments also do not appear in the resulting HTML output:

1{{!-- This comment can contain }}, {{, or {{ ... }} --}}
2
3{{!--
4    Multi-line comments go here.
5    This comment will not appear in the HTML output.
6    {{ handlebars expression }}
7--}}

For more information, see the Handlebars documentation on template comments.

CSS 

CSS Syntax 

  • Place the leading brace on the same line as the selector.

    Single-line comment
    1/* bad */
    2#evg-banner .evg-cta
    3{
    4  color: red;
    5}
    6
    7/* good */
    8#evg-banner .evg-cta {
    9  color: red;
    10}
  • Add one space between the colon and value of each property. No space before the colon.

    Single-line comment
    1/* bad */
    2#evg-banner .evg-cta {
    3  color:red;
    4}
    5
    6/* bad */
    7#evg-banner .evg-cta {
    8  color :red;
    9}
    10
    11/* good */
    12#evg-banner .evg-cta {
    13  color: red;
    14}
  • For each declaration, indent 4 spaces (one press of the TAB key in the template editor) and include a single space after the colon. End each declaration with a semicolon ( ; ). Add a blank line between rulesets.

  • Add one space before the leading brace.

    Single-line comment
    1/* bad */
    2#evg-banner .evg-cta{
    3  color: red;
    4}
    5
    6/* good */
    7#evg-banner .evg-cta {
    8  color: red;
    9}
  • Use the ID selector of the outermost element for every CSS rule to scope them all to the specific template. Use classes instead of element names as selectors that follow the ID selector.

    1#evg-exit-intent-popup .evg-overlay {
    2  position: fixed;
    3  top: 0;
    4  right: 0;
    5  bottom: 0;
    6  left: 0;
    7  width: 100%;
    8  height: 100%;
    9  background-color: #000;
    10  opacity: 0.3;
    11}
    12
    13#evg-exit-intent-popup .evg-popup {
    14  position: fixed;
    15  top: 50%;
    16  left: 50%;
    17  transform: translateX(-50%) translateY(-50%);
    18  width: 500px;
    19  height: 500px;
    20  padding: 20px;
    21  background-color: #fff;
    22  background-position: center bottom;
    23  background-size: cover;
    24  background-repeat: no-repeat;
    25}
  • When using multiple selectors for a ruleset, give each selector its own line.

    1#evg-banner .evg-header,
    2#evg-banner .evg-subheader {
    3  margin-bottom: 1rem;
    4  text-align: center;
    5}
  • Write code in lowercase, including selectors, properties, and property values (except for strings).

    Single-line comment
    1/* bad */
    2#evg-banner .evg-message {
    3  color: #CED5DF;
    4}
    5
    6/* good */
    7#evg-banner .evg-message {
    8  color: #ced5df;
    9}
  • Avoid using element names in conjunction with IDs or classes. Also avoid using ancestor selectors unless necessary.

    1/* bad */
    2div#evg-banner {
    3  color: red;
    4}
    5
    6/* good */
    7#evg-banner {
    8  color: red;
    9}
    10
    11/* bad */
    12body div .evg-cta {
    13  color: red;
    14}
    15
    16/* good */
    17.evg-cta {
    18  color: red;
    19}
  • Don’t add units for “0” values, unless required.

    1/* bad */
    2p {
    3  margin: 0px 10px;
    4}
    5
    6/* good */
    7p {
    8  margin: 0 10px;
    9}
  • Don’t add leading zeros in property values.

    Single-line comment
    1/* bad */
    2p {
    3  font-size: 0.9rem;
    4}
    5
    6/* good */
    7p {
    8  font-size: .9rem;
    9}

Declaration Order 

Group properties by type, in the following order:

  1. Positioning
  2. Display / Box Model
  3. Color
  4. Text
  5. Other

Example:

1#evg-home-hero-banner .evg-btn {
2  position: absolute; /* Positioning */
3  z-index: 10; /* Positioning */
4  top: 0; /* Positioning */
5  left: 0; /* Positioning */
6  display: inline-block; /* Display and Box Model */
7  box-sizing: border-box; /* Display and Box Model */
8  width: 100px; /* Display and Box Model */
9  margin-bottom: 10px; /* Display and Box Model */
10  padding: 10px 5px; /* Display and Box Model */
11  border-radius: 5px; /* Display and Box Model */
12  color: #fff; /* Color */
13  background-color: #215ca0; /* Color */
14  font-size: 16px; /* Text */
15  font-family: Arial, sans-serif; /* Text */
16  text-align: center; /* Text */
17  text-transform: uppercase; /* Text */
18  transition: color 0.15s; /* Other */
19  cursor: pointer; /* Other */
20  user-select: none; /* Other */
21}

Comments 

Use /* ... */ for comments.

Single-line comment
1/* Comment goes here */
2p {
3  color: white;
4  background-color: blue;
5}
Multi-line comment
1/**
2 * Comment
3 * goes
4 * here
5 */
6p {
7  color: red;
8}

Client-side JavaScript 

ES Version 

Global templates are written in ES6 syntax. Use ES5 syntax if there are plans to support IE browsers.

Syntax 

  • Indent nested elements by 4 spaces (one press of the TAB key in the template editor).

  • Break long lines to improve readability, up to 120 characters maximum per line (including whitespace).

  • Add spaces between curly brackets and their contents.

    1// bad
    2const foo = {company:Salesforce}
    3
    4// good
    5const foo = { company:Salesforce}
  • No spaces between square brackets and their contents.

    1// bad
    2const foo = [ a, b, c ];
    3
    4// good
    5const foo = [a, b, c];
  • No spaces between parentheses and their contents.

    1// bad
    2console.log( foo );
    3
    4// good
    5console.log(foo);
    6
    7// bad
    8if ( bar ) {
    9  console.log(bar);
    10}
    11
    12// good
    13if (bar) {
    14  console.log(bar);
    15}
  • No space between the function name and opening parenthesis of the argument list.

    1// bad
    2function foo () {
    3  console.log("foo");
    4}
    5
    6// good
    7function foo() {
    8  console.log("foo");
    9}
  • Add one space before the leading brace.

    1// bad
    2function foo(){
    3  console.log("foo");
    4}
    5
    6// good
    7function foo() {
    8  console.log("foo");
    9}
    10
    11// bad
    12if (foo){
    13  console.log(foo);
    14}
    15
    16// good
    17if (foo) {
    18  console.log(foo);
    19}
  • Add one space before the opening parenthesis in conditional statements.

    1// bad
    2if(foo) {
    3  console.log(foo);
    4}
    5
    6// good
    7if (foo) {
    8  console.log(foo);
    9}
  • When chaining more than two methods, separate each method by a new line and use indentation.

    SalesforceInteractions Namespace
    1// bad
    2SalesforceInteractions.cashDom(".evg-cta").closest(".evg-jumbotron").find(".evg-header").text("Recommended For You").css("text-align", "left");
    3
    4// good
    5SalesforceInteractions.cashDom(".evg-cta")
    6    .closest(".evg-jumbotron")
    7    .find(".evg-header")
    8    .text("Recommended For You")
    9    .css("text-align", "left");
    Evergage Namespace
    1// bad
    2Evergage.cashDom(".evg-cta").closest(".evg-jumbotron").find(".evg-header").text("Recommended For You").css("text-align", "left");
    3
    4// good
    5Evergage.cashDom(".evg-cta")
    6    .closest(".evg-jumbotron")
    7    .find(".evg-header")
    8    .text("Recommended For You")
    9    .css("text-align", "left");

DOM Manipulation 

Use cashDom to select and manipulate elements from the DOM in a similar fashion to jQuery.

SalesforceInteractions Namespace
1SalesforceInteractions.cashDom(selector: <string>, context) => Cash
Evergage Namespace
1Evergage.cashDom(selector: <string>, context) => Cash

Visit the Cash documentation to learn more.

Deferred Rendering 

Depending on the SDK namespace you’re using, use SalesforceInteractions.DisplayUtils.pageElementLoaded or Evergage.DisplayUtils.pageElementLoaded to defer the rendering of the template until the content zone element is loaded on page. To use this utility, you must have the Display Utilities gear installed and enabled for your dataset.

The observer element that monitors for the content zone element to get inserted into its DOM node is set to “body” by default. For performance optimization, this default can be overridden by adding a second selector argument, which is used as the observer element instead.

SalesforceInteractions Namespace
1return SalesforceInteractions.DisplayUtils.pageElementLoaded(selector).then(function (element) {
2  const html = template(context);
3  SalesforceInteractions.cashDom(element).html(html);
4  applyTheme(context);
5});
Evergage Namespace
1return Evergage.DisplayUtils.pageElementLoaded(selector).then(function (element) {
2  const html = template(context);
3  Evergage.cashDom(element).html(html);
4  applyTheme(context);
5});

Visit the Template Display Utilities documentation to learn more.

Comments 

Follow the JSDoc standards for adding JavaScript documentation comments.

Use //... for inline comments.

1const foo = function () {
2  const x = 4;
3  const y = x + 2; // assign the sum of x + 2 to y
4};

Use /** ... */ to comment code blocks, placed it immediately before the block being documented. For multi-line comments, align the stars by indentation.

1/** Comment goes here */
2if (foo) {
3  console.log(foo);
4}
5
6/**
7 * Comment
8 * goes
9 * here
10 */
11function foo(context) {
12  console.log(foo);
13}

Document code blocks with one or more JSDoc tags to describe the function.

1/**
2 * @function incrementDate
3 * @description Increment the date by a given number of days.
4 * @param {string} date - The date, in MM/DD/YYYY format.
5 * @param {number} days - The number of days to increment by.
6 * @return {string} The new date, in MM/DD/YYYY format.
7 */
8function incrementDate(date, days) {
9  // ..
10}

See the complete list of JSDoc tags.

Accessibility 

Semantic Elements 

Use HTML elements for their designed purpose. Whenever possible, use semantic elements to describe the meaning of the content to developers and the browser when appropriate. For example, use heading elements such as h1, h2, and so on to identify headings, anchor elements (a) for navigation between pages, button elements (button) for actions like opening a modal, and input elements (input) for submit buttons (with the type="submit" attribute).

Semantic element examples:

  • button
  • h1
  • form
  • header

Non-semantic element examples:

  • div
  • span

If you use non-semantic elements instead of semantic elements, add ARIA attributes to provide more meaning to the element. For example, if you use a div element instead of the h1 element as a level 1 heading and there is more than one heading on the page, add the role="heading" and aria-level="<heading level number>" ARIA attributes to the non-semantic element (for example, <div role="heading" aria-level="1">Page Heading</div>). Doing so allows assistive technologies like screen readers to identify the non-semantic element as a heading.

Provide an alt attribute for all image elements. In case an image fails to load, the text alternative can convey the meaning of the image in its place (for example, alt="Woman with a shopping cart"). Aim for succinct, descriptive text. If the image is used purely for decoration and is not informative, set the alt tag to an empty string (for example, alt="") so that it can be ignored by assistive technologies. Do not leave out the alt attribute as some screen readers resort to announcing the file name of the image.

For close buttons (‘X’) such as those commonly used in popups, use a button element (button) with an aria-label attribute (for example, aria-label="Close") to provide an accessible name.

The WAVE Evaluation Tool Chrome extension is useful for evaluating the accessibility of your site.

For more information on accessibility, visit Web Content Accessibility Guidelines.

Making Accessible Color Choices 

Ensure that the colors chosen for the text and background satisfy the color contrast ratio as recommended by Web Content Accessibility Guidelines (WCAG). Aim for a color contrast ratio of 4.5 or higher for normal text and 3 for larger text (18 px in bold or 24 px). Visit the WCAG documentation on minimum contrast to learn more.

Use a tool like aremycolorsaccessible.com to check that the color ratio meets at least the AA level.

When using a background image as the backdrop for text, set a fallback background color in case the image does not load. Choose the fallback color such that the text is still visible and the colors meet the color contrast ratio requirements.

Example:

1#evg-hero-banner {
2  background-image: url(‘image.png’);
3  background-color: green;
4}