Template engines help generate dynamic HTML by combining templates with data. This guide covers three popular template engines.

EJS (Embedded JavaScript)

EJS is a simple templating language that lets you generate HTML markup with plain JavaScript.

Syntax

<% %>  <!-- Executed but not output -->
<%= %> <!-- Output the value (HTML escaped) -->

Variables

<h1><%= title %></h1>

Loops

<h1><%= title %></h1>
<ul>
<% for(var i=0; i<supplies.length; i++) { %>
    <li><%= supplies[i] %></li>
<% } %>
</ul>
<%= link_to(name, url) %>

<!-- Example -->
<% for(var i=0; i<supplies.length; i++) { %>
    <li><%= link_to(supplies[i], 'supplies/' + supplies[i]) %></li>
<% } %>

Images

<%= img_tag('images/logo.png') %>

Include

<% include ../partials/nav.ejs %>

Freemarker

Freemarker is a template engine for Java applications.

Basic Syntax

${variable}                    <!-- Interpolation -->
<#directiveName parameters>    <!-- Predefined directive -->
<@mydirective parameters>      <!-- User-defined directive -->
[#-- this is a comment --]     <!-- Comment -->

Variables

<#assign seq = ["foo", "bar", "baz"]>
<#assign x++>
<#assign x="Hello ${user}!">
${x}

Conditionals

<#if x == 1>
    x is 1
<#elseif x == 2>
    x is 2
<#else>
    x is something else
</#if>

Loops

<#list 1..3 as n>
    ${n}
</#list>

<#list users as user>
    <tr>
        <td>${user.firstname}</td>
        <td>${user.lastname}</td>
    </tr>
</#list>

Arrays

<!-- Declaration -->
["foo", "bar", 123.45]

<!-- Access -->
products[5]

<!-- Sub-array -->
products[20..29]

<!-- Concatenation -->
users + ["guest"]

<!-- Methods -->
${testSequence?size}
${testSequence?join(", ")}

Maps

<!-- Declaration -->
{"name":"green mouse", "price":150}

<!-- Access -->
user.name
user["name"]

<!-- Iteration -->
<#list user?keys as prop>
    ${prop} = ${user.get(prop)}
</#list>

<!-- Concatenation -->
passwords + { "joe": "secret42" }

Strings

"Foo" or 'Foo'
"It's \"quoted\""
${r"${raw}"} <!-- Raw string -->

<!-- Operations -->
name[0]           <!-- Character -->
name[0..4]        <!-- Substring (inclusive) -->
name[0..<5]       <!-- Substring (exclusive) -->
name[5..]         <!-- From index to end -->

<!-- Concatenation -->
<#assign s = "Hello " + user + "!">

<!-- Methods -->
${testString?upper_case}
${testString?cap_first}

Numbers

${1.999?int}   <!-- 1 -->
${-1.999?int}  <!-- -1 -->

Type Casting

${3 + "5"}              <!-- "35" (string concatenation) -->
123?string              <!-- Number to string -->
${married?string("yes", "no")}  <!-- Boolean to string -->

Functions

<#function avg x y>
    <#return (x + y) / 2>
</#function>

${avg(10, 20)}

Macros

<#macro greet name>
    Hello, ${name}!
</#macro>

<@greet name="John"/>

<!-- With default values -->
<#macro defaultHead title="Default Title">
    <title>${title}</title>
</#macro>

<!-- Nested content -->
<#macro box>
    <div class="box">
        <#nested>
    </div>
</#macro>

<@box>
    <p>Content inside box</p>
</@box>

Exception Handling

<#attempt>
    Optional: ${thisMayFail}
<#recover>
    Oops! Something went wrong.
</#attempt>

<!-- Missing values -->
${mouse!"No mouse."}  <!-- Default if null -->
<#if mouse??>         <!-- Check if exists -->
    Mouse found
</#if>

Import and Include

<#import "/mylib.ftl" as my>
<#include "/footer/${company}.html">

Operators

<!-- Arithmetic -->
(x * 1.5 + 10) / 2 - y % 100

<!-- Comparison -->
x == y, x != y, x < y, x > y, x >= y, x <= y
x lt y, x lte y, x gt y, x gte y

<!-- Logical -->
!registered && (firstVisit || fromEurope)

<!-- Assignment -->
=, +=, -=, *=, /=, %=, ++, --

Compute Audience

For JavaScript or URL values (non-human readable):

<a href="/product?id=${product.id?c}">Details</a>
${someBoolean?c}

Thymeleaf

Thymeleaf is a modern server-side Java template engine for Spring applications.

Setup

<html xmlns:th="http://thymeleaf.org">

Display Values

<h4 th:text="${user.name}"></h4>

<p th:if="${param.error}">
    Bad Credentials: ${param.error}
</p>

Conditionals

<div th:if="${condition}">
    Shown if condition is true
</div>

<div th:unless="${condition}">
    Shown if condition is false
</div>

<div th:switch="${user.role}">
    <p th:case="'admin'">Admin User</p>
    <p th:case="'user'">Regular User</p>
    <p th:case="*">Unknown Role</p>
</div>

Loops

<tr th:each="user : ${users}">
    <td th:text="${user.name}">Name</td>
    <td th:text="${user.email}">Email</td>
</tr>

Attributes

<a th:href="@{/users/{id}(id=${user.id})}">View User</a>
<img th:src="@{/images/logo.png}">
<input th:value="${user.name}">

Comparison

Feature EJS Freemarker Thymeleaf
Platform Node.js Java Java/Spring
Syntax <%= %> ${} th:*
Natural Templates No No Yes
Logic in Template Yes Yes Limited
Learning Curve Low Medium Medium

Each template engine has its strengths:

  • EJS - Simple JavaScript templating for Node.js
  • Freemarker - Powerful features for Java applications
  • Thymeleaf - Natural templates that work as valid HTML

Choose the template engine that best fits your technology stack and project requirements.